Thread class
Thread
Runnable interface
Extending Thread
run method
main
class InputThread extends Thread {
public void run() {
... // main body of thread
}
}
Implementing Runnable
run method (as above)
class ActiveCounter extends Counter implements Runnable {
public void run() {
... // main body of thread
}
}
Starting a Thread
InputThread it = new InputThread();
Thread t = new InputThread();
Thread t2 = new Thread(new ActiveCounter());
Runnable r = new ActiveCounter(); Thread t3 = new Thread(r);
start method on the created object
run method
start method contains the 'magic' needed to
create the actual thread
run is
(indirectly) invoked
run method directly would merely cause it
to execute in the same thread as you invoke it
it.start();
t.start();
new InputThread().start();
new Thread(new ActiveCounter()).start();
NEW - created but start hasn't been invoked yet
ALIVE - start has been invoked. Two substates
RUNNABLE - Ready to run
BLOCKED - waiting for a certain event
DEAD - have returned from run method
setPriority method
yield method (yielding)
sleep, join, or wait (blocking)
A Simple Clock Applet
import java.awt.*;
import java.applet.*;
import java.util.*;
public class Clock0 extends Applet {
public void paint(Graphics g) {
String display = new Date() + "";
FontMetrics fm = g.getFontMetrics();
int stringWidth = fm.stringWidth(display);
int screenWidth = getWidth();
g.drawString(display, (screenWidth - stringWidth)/2, 100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
repaint();
}
}
Thread.sleep - static method in Thread that causes the current thread to
sleep for specified milliseconds (1000ths of a second).
paint is called it updates the display and calls repaint
A Related Applet: A Stopwatch
import java.util.*;
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.text.*;
public class Clock1 extends Applet implements ActionListener {
public void init() {
setLayout(new FlowLayout(FlowLayout.CENTER));
clock = new Label(simpleDateFormat.format(new Date(0)));
add(clock);
b = new Button("Start");
add(b);
b.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
paused = !paused;
if (!paused) {
b.setLabel("Pause");
if (firstTime) {
firstTime = false;
startClock();
}
}
else
b.setLabel("Resume");
}
void startClock() {
Date startDate = new Date();
while (true) {
if (!paused) {
Date duration = new Date(new Date().getTime() - startDate.getTime());
clock.setText(simpleDateFormat.format(duration));
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");
boolean paused = true;
Button b;
Label clock;
boolean firstTime = true;
}
startClock to be invoked
startClock contains infinite loop
actionPerformed...
actionPerformed never returns to whoever called it ...
Fixing the Stopwatch
startClock
Diag class that helps us see who's doing what
Diag contains a single static method that accepts a message and prints it together
with the name of the currently executing thread
class Diag {
static void threadPrint(String what) {
System.err.println(what + ": " + Thread.currentThread().getName());
}
}
Here's the Applet
import java.util.*;
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.text.*;
public class Clock2 extends Applet implements ActionListener {
public void init() {
Diag.threadPrint("init");
setLayout(new FlowLayout(FlowLayout.CENTER));
Label clock = new Label(simpleDateFormat.format(new Date(0)));
add(clock);
b = new Button("Pause");
b.setForeground(Color.red);
add(b);
b.addActionListener(this);
clockThread = new Clock2Thread(clock);
clockThread.start();
}
public void actionPerformed(ActionEvent e) {
Diag.threadPrint("actionPerformed");
boolean paused = clockThread.togglePaused();
if (!paused) {
b.setForeground(Color.red);
b.setLabel("Pause");
}
else {
b.setForeground(DARK_GREEN);
b.setLabel("Resume");
}
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");
static final Color DARK_GREEN = new Color(0, 100, 0);
Button b;
Clock2Thread clockThread;
}
Clock2Thread object and the invocation of start
actionPerformed method controls the clock thread via the
togglePaused method
... and here's the thread ...
import java.awt.*;
import java.util.*;
import java.text.*;
class Clock2Thread extends Thread {
Clock2Thread(Label clock) {this.clock = clock;}
boolean togglePaused() {
Diag.threadPrint("togglePaused");
paused = !paused;
return paused;
}
public void run() {
Diag.threadPrint("run");
Date startDate = new Date();
int count = 0;
while (true) {
if (!paused) {
Date duration = new Date(new Date().getTime() - startDate.getTime());
clock.setText(simpleDateFormat.format(duration));
count++;
if (count > 10) {
Diag.threadPrint("tick");
count = 0;
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");
boolean paused = false;
Label clock;
}
Ensuring Thread Safety in Java
synchronized keyword
join, wait
and notify
An Example - A credit card system
Another Example-- Mutli-Threaded Quicksort
join
join
//Dispatcher Thread
while (1) {
request = getNextRequest()
handOffRequest(request)
}
//Worker Thread
while (1) {
request = waitForWork()
found = lookInCache(request, page)
if (!found)
readPageFromDisk(request, page)
returnPage(page)
}
#3 - Inputting, Processing and Outputting Blocks of Data