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