What We Will Cover
Illuminations
Questions on Completed Assignments?
^ top
13.1: Thread Fundamentals
Objectives
At the end of the lesson the student will be able to:
- Explain the basic difference between a program that runs in a single thread and a program that runs under multiple threads.
- Name three common reasons for using threads in a Java application.
- List the three Java API classes or interfaces that have methods related to threading.
- Use the
Thread class or the Runnable interface to create a thread.
- Explain the advantage of creating a thread by extending the
Runnable interface rather than by inheriting the Thread class.
- Use the
interrupt() method and the InterruptedException class to create a thread that can be interrupted.
|
^ top
13.1.1: About Threads
Typical Uses for Threads
- To give the appearance of parallel processing
- To make use of multiple processors and perform tasks in parallel
- Multiple-processor chips are now shipping
- May cause a dramatic shift in the programming paradigm
- When there are many tasks to perform and one is often waiting

- To improve the responsiveness of a user interface
- Allow time-consuming tasks to occur in the background
^ top
13.1.2: Classes and Interfaces for Working with Threads
- There are two main classes and one interface commonly used for working with threads
- These classes and interfaces are shown in the following table:
| Class/Interface |
Description |
| Thread |
A class that defines a thread. |
| Runnable |
An interface that must be implemented by the class of any object that is going to be executed by a thread. |
| Object |
Several methods of the Object class are used for threading. |
- The inheritance relationship of these modules is shown in the following diagram:

- The
Runnable interface has just one method: run()
- Any thread calls the
run() method when it starts running
- In addition, threads end when they complete the
run() method
- Constructors and methods of the
Thread class are shown below
- We will cover these methods in the following sections
- In addition, methods of the
Object class used for threading are shown
- These methods are used for signal-wait synchronization, which we cover toward the end of this lesson
Commonly Used Constructors of the Thread Class
| Constructor |
Description |
| Thread() |
Creates a new Thread object with default settings. |
| Thread(Runnable) |
Creates a new Thread object from any object that implements the Runnable interface |
| Thread(String) |
Creates a new Thread object with the specified name. |
| Thread(Runnable, String) |
Creates a new Thread object with the specified name from any object that implements the Runnable interface. |
Commonly Used Methods of the Thread Class
| Method |
Description |
| run() |
Called by the thread scheduler to run the thread. All subclasses of Thread should override this method. |
| start() |
Called to start the execution of the thread. |
| currentThread() |
A static method that returns a reference to the currently executing thread. |
| sleep(long millis) |
A static method that stops the current thread from executing for the specified number of milliseconds. |
| yield() |
Causes the currently executing thread object to temporarily pause and allow other threads to execute. |
| getName() |
Returns the name of the thread. |
| getState() |
Returns the state of the thread. |
| interrupt() |
Interrupts this thread. |
| isInterrupted() |
Tests whether this thread has been interrupted. |
| join() |
Waits for the thread on which it is called to finish and join the calling thread. |
| setPriority(int) |
Changes the priority of the thread. |
Methods of the Object Class Used for Threading
| Method |
Description |
| wait() |
Causes current thread to wait until another thread invokes the notify() method or the notifyAll() method for the current object. |
| notify() |
Wakes up a single arbitrary thread that is waiting on this object's monitor. |
| notifyAll() |
Wakes up all threads that are waiting on this object's monitor. |
^ top
13.1.3: Using the sleep() Method
- When you review the list of methods in the
Thread class, you might notice the sleep() method
- This method simply causes the current from running for a period of time
- Since it is a static method, we can call it without a reference to the current Thread object
However, the method can throw an InterruptedException which we must handle
- Thus, we could write a simple method to pause the current thread for a number of milliseconds
- For instance:
public void pause(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
System.out.println("Thread interrupted!");
System.exit(1);
}
}
This might be useful for simple animation like that shown in the example below
Example of Simple Animation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
// Unresponsive GUI
public class Bubbles extends JFrame
implements ActionListener {
public final static int X_LOC = 100, Y_LOC = 100,
WIDTH = 400, HEIGHT = 300;
public static final int DELAY = 100;
public static final int COLORS = 16581375;
public static final int MAX_SIZE = 40;
public static final int NUM_SHAPES = 400;
private JButton startButton;
private JButton stopButton;
private JPanel canvas;
public static void main(String[] args) {
new Bubbles();
}
public Bubbles() {
super("Bubbles Animation");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container pane = getContentPane();
canvas = new JPanel();
pane.add(canvas, BorderLayout.CENTER);
startButton = new JButton("Start");
stopButton = new JButton("Stop");
JPanel panel = new JPanel();
panel.add(startButton);
startButton.addActionListener(this);
panel.add(stopButton);
stopButton.addActionListener(this);
pane.add(panel, BorderLayout.SOUTH);
setBounds(X_LOC, Y_LOC, WIDTH, HEIGHT);
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source == startButton) {
draw();
} else if (source == stopButton) {
System.out.println("Goodbye!");
System.exit(0);
}
}
public void draw() {
Graphics g = canvas.getGraphics();
Color c;
for (int i = 0; i < NUM_SHAPES; i++) {
int x1 = (int)(Math.random() * WIDTH);
int y1 = (int)(Math.random() * HEIGHT);
int size = (int)(Math.random() * MAX_SIZE);
c = new Color((int)(Math.random() * COLORS));
g.setColor(c);
g.drawOval(x1, y1, size, size);
pause(DELAY);
}
}
public void pause(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
System.out.println("Thread interrupted!");
System.exit(0);
}
}
}
|
^ top
13.1.4: Subclassing Class Thread
- When we run the previous example, we notice that we cannot use any of the controls until the animation is finished
- To fix this nonresponsive interface, we can use a thread to run the animation in the background
- This will free up the GUI thread and allow us to use the controls during the animation
- There are two ways to implement a thread
- Subclass
Thread and override the run method
- Implement the
Runnable interface
- The most straightforward way to implement threads is to subclass the
Thread class
- We implement the
Thread subclass as an inner class to keep our animation class self-contained
private class Bubbler extends Thread
The Thread class implements the run() method with an empty body
public void run() { }
Thus any subclass of Thread is expected to override the run() method
We put our animation code in the run() method since that is where the thread runs
public void run() {
// animation code
}
Note that we do not call run() directly
Instead, to start the thread, we call the start() method
Bubbler bub = new Bubbler();
bub.start();
The JVM calls run() after we call the start() method
- This allows the JVM to set up the internal data structures needed to handle the thread
When start() is called, the thread starts executing independently
Example of Simple Animation Subclassing Thread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
// Multithreaded GUI
public class Bubbles2 extends JFrame
implements ActionListener {
public final static int X_LOC = 100, Y_LOC = 100,
WIDTH = 400, HEIGHT = 300;
public static final int DELAY = 100;
public static final int COLORS = 16581375;
public static final int MAX_SIZE = 40;
public static final int NUM_SHAPES = 400;
private JButton startButton;
private JButton stopButton;
private JPanel canvas;
public static void main(String[] args) {
new Bubbles2();
}
public Bubbles2() {
super("Bubbles Animation");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container pane = getContentPane();
canvas = new JPanel();
pane.add(canvas, BorderLayout.CENTER);
startButton = new JButton("Start");
stopButton = new JButton("Stop");
JPanel panel = new JPanel();
panel.add(startButton);
startButton.addActionListener(this);
panel.add(stopButton);
stopButton.addActionListener(this);
pane.add(panel, BorderLayout.SOUTH);
setBounds(X_LOC, Y_LOC, WIDTH, HEIGHT);
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source == startButton) {
Bubbler bub = new Bubbler();
bub.start();
} else if (source == stopButton) {
System.out.println("Goodbye!");
System.exit(0);
}
}
private class Bubbler extends Thread {
public void run() {
Graphics g = canvas.getGraphics();
Color c;
for (int i = 0; i < NUM_SHAPES; i++) {
int x1 = (int)(Math.random() * WIDTH);
int y1 = (int)(Math.random() * HEIGHT);
int size = (int)(Math.random() * MAX_SIZE);
c = new Color((int)(Math.random() * COLORS));
g.setColor(c);
g.drawOval(x1, y1, size, size);
pause(DELAY);
}
}
public void pause(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
System.out.println("Thread interrupted!");
System.exit(0);
}
}
}
}
|
^ top
13.1.5: Implementing Interface Runnable
- There are times when you would rather not make a thread class subclass
Thread
- The alternative is to make your class implement the
Runnable interface
- The
Runnable interface has only one method to implement:
public void run();
A class that implement Runnable must still run from an instance of the class Thread
This is usually done by passing the Runnable object as an argument to a thread constructor
Here is a template of how this is often done:
public class MyClass implements Runnable {
public void run() {
// code to run like when subclassing Thread
}
// Somewhere you start the thread
Thread runner = new Thread(this);
runner.start();
}
We apply this template to our animation in the following example
Example of Simple Animation Implementing Runnable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
// Multithreaded runable GUI
public class Bubbles3 extends JFrame
implements ActionListener, Runnable {
public final static int X_LOC = 100, Y_LOC = 100,
WIDTH = 400, HEIGHT = 300;
public static final int DELAY = 100;
public static final int COLORS = 16581375;
public static final int MAX_SIZE = 40;
public static final int NUM_SHAPES = 400;
private JButton startButton;
private JButton stopButton;
private JPanel canvas;
public static void main(String[] args) {
new Bubbles3();
}
public Bubbles3() {
super("Bubbles Animation");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container pane = getContentPane();
canvas = new JPanel();
pane.add(canvas, BorderLayout.CENTER);
startButton = new JButton("Start");
stopButton = new JButton("Stop");
JPanel panel = new JPanel();
panel.add(startButton);
startButton.addActionListener(this);
panel.add(stopButton);
stopButton.addActionListener(this);
pane.add(panel, BorderLayout.SOUTH);
setBounds(X_LOC, Y_LOC, WIDTH, HEIGHT);
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source == startButton) {
Thread runner = new Thread(this);
runner.start();
} else if (source == stopButton) {
System.out.println("Goodbye!");
System.exit(0);
}
}
public void run() {
Graphics g = canvas.getGraphics();
Color c;
for (int i = 0; i < NUM_SHAPES; i++) {
int x1 = (int)(Math.random() * WIDTH);
int y1 = (int)(Math.random() * HEIGHT);
int size = (int)(Math.random() * MAX_SIZE);
c = new Color((int)(Math.random() * COLORS));
g.setColor(c);
g.drawOval(x1, y1, size, size);
pause(DELAY);
}
}
public void pause(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
System.out.println("Thread interrupted!");
System.exit(0);
}
}
}
|
^ top
13.1.6: Interrupting Threads
- Note that a thread ends by finishing its
run() method
- There is no reliable method that another thread can call to stop a thread
- The correct coding practice is for the thread to check periodically if it should end
public void run() {
while (stop == false) {
// perform actions repeatedly
}
}
To support this approach, the Thread class has an interrupt() method
Calling the interrupt() method either:
- Sets the status of the thread to interrupted
- Invokes an exception
To check the interrupt status, you use the method isInterrupted()
However, if the thread is sleeping (blocked), it cannot execute the code that sets the interrupted status
Instead, the thread clears the interrupt status and throws an InterruptedException
Thus we must consider both cases and implement code to:
- Stop a thread while executing
- Stop a thread if blocked
To do this, we create a boolean instance variable named stop
private boolean stop;
We redefine the Stop button so that whenever it is pressed we set the stop variable to true
if (source == stopButton) {
if (runner != null) {
stop = true;
runner.interrupt();
}
}
Since the Stop button can be pressed without pressing the Start button, we protect against this case with an if statement as shown
Next we code the run() method to check for a stop condition each time though its loop
for (int i = 0; i < NUM_SHAPES && !stop; i++)
In addition to these exceptions, there are others that may be thrown.
For our simple application, however, we will let these exceptions be caught by the general exception handler
The complete example is shown below
Example of Simple Animation With Stop Enabled
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
// Stopable GUI
public class Bubbles4 extends JFrame
implements ActionListener, Runnable {
public final static int X_LOC = 100, Y_LOC = 100,
WIDTH = 400, HEIGHT = 300;
public static final int DELAY = 100;
public static final int COLORS = 16581375;
public static final int MAX_SIZE = 40;
public static final int NUM_SHAPES = 400;
private JButton startButton;
private JButton stopButton;
private JPanel canvas;
private Thread runner;
private boolean stop;
public static void main(String[] args) {
new Bubbles4();
}
public Bubbles4() {
super("Bubbles Animation");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container pane = getContentPane();
canvas = new JPanel();
pane.add(canvas, BorderLayout.CENTER);
startButton = new JButton("Start");
stopButton = new JButton("Stop");
JPanel panel = new JPanel();
panel.add(startButton);
startButton.addActionListener(this);
panel.add(stopButton);
stopButton.addActionListener(this);
pane.add(panel, BorderLayout.SOUTH);
setBounds(X_LOC, Y_LOC, WIDTH, HEIGHT);
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source == startButton) {
stop = false;
runner = new Thread(this);
runner.start();
} else if (source == stopButton) {
if (runner != null) {
stop = true;
runner.interrupt();
}
}
}
public void run() {
Graphics g = canvas.getGraphics();
Color c;
for (int i = 0; i < NUM_SHAPES && !stop; i++) {
int x1 = (int)(Math.random() * WIDTH);
int y1 = (int)(Math.random() * HEIGHT);
int size = (int)(Math.random() * MAX_SIZE);
c = new Color((int)(Math.random() * COLORS));
g.setColor(c);
g.drawOval(x1, y1, size, size);
pause(DELAY);
}
}
public void pause(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
System.out.println("Thread interrupted!");
}
}
}
|
More Information
^ top
13.1.7: Summary
- A thread is a single flow of control through a program
- Java allows the programmer to write programs with multiple threads
- Using threads, you can define tasks that act independently of each other
- A thread scheduler determines which thread to run next
- Multithreading is typically used to:
- To give the appearance of parallel processing
- To make use of multiple processors and perform tasks in parallel
- When there are many tasks to perform and one is often waiting
- To improve the responsiveness of a user interface
- You can create a thread by either:
- Extending the
Thread class and instantiating the new class
- Implementing the
Runnable interface and passing a reference of the object to a constructor of the Thread class
- To start a thread, you call the
start() method of the Thread class
- You never call the
run() method directly
- Stopping a thread is more difficult than starting one
- The way to end a thread is to finish its run() method
- Each thread is responsible for checking itself periodically to see if it should end
- You can use methods
interrupt() and isInterrupted() to help with this task
- However, if a thread is blocked, it cannot execute the code that sets the interrupted status
- Instead, the thread clears the interrupt status and throws an
InterruptedException
- Thus, you must write code that works both if the thread is running and if the thread is blocked
^ top
Exercise 13.1
Take one minute to prepare an answer to the following questions
- What is a thread?
- What are three typical reasons for using threads? (answer)
- What two classes and one interface do you use to work with threads?
- What two techniques can you use to create a thread?
^ top
13.2: Using Timers
Objectives
At the end of the lesson the student will be able to:
- Explain the task of the event thread
- Describe when to use the timer classes
- Use the
Timer class of the javax.swing package to schedule tasks.
- Use the
Timer and TimerTask classes of the java.util package to schedule tasks.
|
^ top
13.2.1: Implicit Event Thread
- Every GUI program has two threads
- The main thread is the one executing the
main() method
- The other thread is called the event-dispatching thread, or just event thread
- The event thread detects GUI events and invokes methods like
paintComponent() and various listener methods like actionPerformed()
- The main thread often terminates after launching the GUI
- To show that two threads are operating, we can put the main thread in a loop
while (true) { // main thread never ends
count++;
Thread.currentThread().sleep(ONE_SECOND);
System.out.println("Count = " + count);
}
Before this loop, we can create a GUI which responds to our controls even when the main thread is sleeping
The code is shown below
Example Program Showing the Event Thread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventThread {
public static final int ONE_SECOND = 1000;
public static void main(String[] args)
throws InterruptedException {
createGUI();
int count = 0;
while (true) { // main thread never ends
count++;
Thread.currentThread().sleep(ONE_SECOND);
System.out.println("Count = " + count);
}
}
public static void createGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
Container pane = frame.getContentPane();
JButton counter =
new JButton("Click Me!");
counter.addActionListener(new ClickCounter());
pane.add(counter, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
class ClickCounter implements ActionListener {
private int count = 0;
public void actionPerformed(ActionEvent e) {
count++;
System.out.println("Total clicks = " + count);
}
}
|
^ top
13.2.2: Using Swing Timers
- Normally, you should not use threads when working with Swing components
- This is because Swing components are not generally thread safe
- This means that if multiple threads manipulate a Swing component, the results may not be correct
- Instead, most access to Swing components should be done through the event thread
- Some exceptions are the
repaint() and addXXXListener() methods
- However, sometimes you need to perform some task repeatedly in Swing -- like animation
- To make this easy, Java has the
javax.swing.Timer class
- The Swing
Timer class works by firing periodic action events
- Thus, using a Swing timer is like working with Swing event handlers
- Constructors and methods of the Swing
Timer class are shown in the table below
Commonly-Used Constructors and Methods from javax.swing.Timer
More Information
^ top
13.2.3: Example Using Swing Timers
- To implement the timer you first need to code a class to receive action events
public class Bubbles5 extends JFrame
implements ActionListener {
Then we code some methods to control the animation
public void initAnimation() {
timer = new javax.swing.Timer(DELAY, this);
timer.setInitialDelay(0);
timer.setCoalesce(true);
}
public void startAnimation() {
timer.start();
}
public void stopAnimation() {
timer.stop();
}
And finally we code and action event handler for the timer
if (source == timer) {
if (numShapes < NUM_SHAPES) {
drawBubble();
numShapes++;
} else {
stopAnimation();
}
}
An complete example program using a Swing timer is shown below:
Example Using a Swing Timer for Animation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
// Using Swing Timers
public class Bubbles5 extends JFrame
implements ActionListener {
public final static int X_LOC = 100, Y_LOC = 100,
WIDTH = 400, HEIGHT = 300;
public static final int DELAY = 100;
public static final int COLORS = 16581375;
public static final int MAX_SIZE = 40;
public static final int NUM_SHAPES = 400;
private JButton startButton;
private JButton stopButton;
private JPanel canvas;
private Thread runner;
private boolean stop;
// For animation
private javax.swing.Timer timer;
private int numShapes;
public static void main(String[] args) {
new Bubbles5();
}
public Bubbles5() {
super("Bubbles Animation");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container pane = getContentPane();
canvas = new JPanel();
pane.add(canvas, BorderLayout.CENTER);
startButton = new JButton("Start");
stopButton = new JButton("Stop");
JPanel panel = new JPanel();
panel.add(startButton);
startButton.addActionListener(this);
panel.add(stopButton);
stopButton.addActionListener(this);
pane.add(panel, BorderLayout.SOUTH);
initAnimation();
setBounds(X_LOC, Y_LOC, WIDTH, HEIGHT);
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source == startButton) {
startAnimation();
} else if (source == stopButton) {
stopAnimation();
} else if (source == timer) {
if (numShapes < NUM_SHAPES) {
drawBubble();
numShapes++;
} else {
stopAnimation();
}
}
}
public void drawBubble() {
Graphics g = canvas.getGraphics();
Color c;
int x1 = (int)(Math.random() * WIDTH);
int y1 = (int)(Math.random() * HEIGHT);
int size = (int)(Math.random() * MAX_SIZE);
c = new Color((int)(Math.random() * COLORS));
g.setColor(c);
g.drawOval(x1, y1, size, size);
}
public void initAnimation() {
timer = new javax.swing.Timer(DELAY, this);
timer.setInitialDelay(0);
timer.setCoalesce(true);
}
public void startAnimation() {
timer.start();
}
public void stopAnimation() {
timer.stop();
}
}
|
^ top
13.2.4: Using Utility Timers
- The
javax.swing.Timer class relies on the event thread
- An approach that does not need the event thread is use the
Timer and TimerTask classes of the java.util package to schedule tasks
- A
Timer object can schedule one or more TimerTask objects to perform actions once or repeatedly
- To use the utility timer:
- Code a class that extends the
TimerTask and override its run() method
class Task extends TimerTask {
public void run() {
// code to perform the task
}
}
- Create an object from the
Timer class
Timer timer = new Timer();
- Use the
schedule() method of the Timer object to call TimerTask objects at specified times or intervals
timer.schedule(new Task(), seconds);
- Commonly used constructors and methods of
TimerTask and Timer are shown below
Commonly-Used Constructors and Methods from TimerTask
| Constructor/Method |
Description |
| TimerTask() |
Creates a new TimerTask object. |
| run() |
Must be overridden to handle specific actions for this timer task. |
Commonly-Used Constructors and Methods from Timer
Further Information
^ top
13.2.5: Example Using the Utility Timer
- You can use the
Timer class to schedule a task for execution in many ways
- For instance, can schedule a task to be performed after a delay
- The schedule method of
Timer is overloaded to allow scheduling tasks in a number of ways
- For instance, you can schedule for a specific point in time using a
Date object
//Get the Date corresponding to 9:01:00 PM today.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 21);
calendar.set(Calendar.MINUTE, 1);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer = new Timer();
timer.schedule(new Task(), time);
Also, you can schedule tasks to repeat at fixed intervals
const int initialDelay = 0;
const int fixedRate = 1000; // in milliseconds
timer = new Timer();
timer.schedule(new Task(), initialDelay, fixedRate);
Following program demonstrates using a utility timer in a simple way
Example Using a Utility Timer to Schedule Tasks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import java.util.*;
import javax.swing.JOptionPane;
public class Scheduler {
public static void main(String args[]) {
System.out.println("Scheduling task");
new Scheduler(5);
System.out.println("Task scheduled");
}
public Scheduler(int seconds) {
seconds *= 1000;
Timer timer = new Timer();
timer.schedule(new Task(), seconds);
}
private class Task extends TimerTask {
public void run() {
JOptionPane.showMessageDialog(null,
"Time's up!");
System.exit(0);
}
}
}
|
Example Using a Utility Timer to Schedule an Alarm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import java.util.*;
import javax.swing.JOptionPane;
public class Alarm {
private java.util.Timer timer;
public static void main(String[] args) {
System.out.println("Scheduling alarm");
Alarm alarm = new Alarm();
System.out.println("Alarm scheduled");
}
public Alarm() {
GregorianCalendar dateTime =
new GregorianCalendar(2005,
Calendar.JUNE, 3, 17, 0);
Date alarmDateTime = dateTime.getTime();
timer = new Timer();
timer.schedule(new AlarmTask(), alarmDateTime);
}
}
class AlarmTask extends TimerTask {
public void run() {
JOptionPane.showMessageDialog(null,
"Schools out!");
System.exit(0);
}
}
|
^ top
13.2.6: Summary
- Every GUI program runs a second thread called the event thread
- The event thread is responsible for keeping the GUI up to date
- For example, the thread schedules repainting, fires events and runs event listener code
- Swing components should only be run in the event thread
- To allow you to run repeated tasks on Swing components, like animation, you can use the
javax.swing.Timer class
- The Swing timer will periodically generate an
ActionEvent
- Then you can write action event listener code to handle the periodic tasks
- Java also supplies another general purpose time called the utility timer
- This timer uses its own thread and does not rely on the event thread
- The utility timer is more versatile than the Swing timer
- To use the utility timer:
- Code a class that extends the
TimerTask and override its run() method
class Task extends TimerTask {
public void run() {
// code to perform the task
}
}
- Create an object from the
Timer class
Timer timer = new Timer();
- Use the
schedule() method of the Timer object to call TimerTask objects at specified times or intervals
timer.schedule(new Task(), seconds);
^ top
Exercise 13.2
Take one minute to prepare an answer to the following questions:
- How many threads run, at a minimum, for every GUI program?
- What are the steps to create a utility timer?
- Which of the following methods would we use to schedule a task for execution once a minute starting at 9:00 PM tonight?
schedule(TimerTask task, long delay, long period)
schedule(TimerTask task, Date firstTime, long period)
scheduleAtFixedRate(TimerTask task, long delay, long period)
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
^ top
13.3: Using Threads Cooperatively
Objectives
At the end of the lesson the student will be able to:
- List the six states of a thread, and describe the status of a thread in each state.
- Explain the difference between the
sleep() and yield() methods
- Set the priority of threads
- Describe how to run threads cooperatively
|
^ top
13.3.1: More About Threads
- So far we have been using only two threads: the main thread and one child thread
- However, our programs can contain potentially many threads
- When this occurs we need to consider issues such as
- When does each thread run?
- How do we control the execution?
- In what state is the thread?
- To answer these questions, we need to better understand how threads operate
Life Cycle of a Thread
- Running a thread is different than executing other program code
- Threads have a definite starting point and a definite end point
- Over their lifetime, they can exist in one of several states
- These states are shown in the following diagram (from The Life Cycle of a Thread)

- Note that this is not a complete state diagram but an overview of a thread's life cycle
- "Not Runnable" can be one of three different states:
- Blocked
- Waiting
- Timed Waiting
- Also notice that there is no way to tell the thread scheduler when to run a particular thread
- We can put a thread into a wait state
- In addition, we can give the thread scheduler hints about what thread to run
- However, there is no way to direct the thread scheduler to run one particular thread out of many
- This lets the thread scheduler keep threads running even if one gets blocked by I/O or other causes
Thread States
| State |
Description |
| New |
The threads has been created by calling it's constructor, but has not yet started running. |
| Runnable |
The thread's start methods has been called and the thread is available to the thread scheduler. The thread may be running or may be waiting in a queue for an opportunity to run. |
| Blocked |
The thread has been temporarily removed from the Runnable state waiting for a monitor lock. |
| Waiting |
The thread is waiting for another thread to perform a task. This state can be entered through calls to Object.wait() or Thread.join(). |
| Timed Waiting |
The thread is waiting with a specified waiting time for another thread to perform a task. |
| Terminated |
The thread's run method has ended. |
^ top
13.3.2: Example of Multiple Threads
- When a program starts, one thread starts running immediately: the main thread
- All other threads are spawned from the main thread
- In the following example, you can see two threads spawned from the main thread
- Inside each thread, notice the use of the
yield() method
- Method yield() pauses currently executing thread object and allows other threads to execute
- This makes sure that each thread gets a chance to run
Example of Multiple Threads
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public class CountDownApp {
public static void main(String[] args) {
Thread t0 = new CountDownEven();
Thread t1 = new CountDownOdd();
t0.start();
t1.start();
System.out.println("Main thread done");
}
}
class CountDownEven extends Thread {
public void run() {
for (int i = 10; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
class CountDownOdd extends Thread {
public void run() {
for (int i = 9; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
|
^ top
13.3.3: Using Methods getState() and join()
- Often you will want one thread to finish before another
- To make one thread wait for another to finish, you use the join() method
- The name of the
join() method comes from the idea of one thread waiting until another thread "joins it"
- Another method that is often useful is getState()
- Method
getState() returns one of the six states listed in the beginning of this section
- The following code shows a simple example using both of these methods
- The
main() method waits to exit until other threads have finished
- Unlike most previous examples
- In addition, we use the
getState() method to display the state of the threads during their life cycle
Example Using getState() and join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public class CountDownJoinApp {
public static void main(String[] args)
throws InterruptedException {
Thread t0 = new CountDownEven();
Thread t1 = new CountDownOdd();
System.out.println(t0.getName()
+ " " + t0.getState());
System.out.println(t1.getName()
+ " " + t1.getState());
t0.start();
t1.start();
System.out.println(t0.getName()
+ " " + t0.getState());
System.out.println(t1.getName()
+ " " + t1.getState());
t0.join();
t1.join();
System.out.println(t0.getName()
+ " " + t0.getState());
System.out.println(t1.getName()
+ " " + t1.getState());
System.out.println("Main thread done");
}
}
class CountDownEven extends Thread {
public void run() {
for (int i = 10; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
class CountDownOdd extends Thread {
public void run() {
for (int i = 9; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
|
^ top
13.3.4: Thread Priorities and Scheduling
- Each thread has a priority that helps the thread scheduler decide when to run a thread
- Threads are selected to run based on their priority relative to other Runnable threads
- The JVM system chooses a runnable thread with the highest priority to run
- Only when all higher priority threads stop, yield, or becomes not runnable for some reason will a lower priority thread start executing
- Three constants for thread priorities:
Thread.MIN_PRIORITY
Thread.NORM_PRIORITY
Thread.MAX_PRIORITY
- Java thread priorities can range from 1-10
- Any thread currently running will continue until one of the following happens
- A higher priority thread becomes runnable
- Its
run() method exits
- It yields
- On systems that support time-slicing, its time allotment expires
- The job of the scheduler is to keep the highest priority thread running
- If time-slicing is available, the scheduler keeps equally high-priority threads running in round-robin fashion
- Note that threads on different systems can have very different behavior
- Most inconsistencies occur when threads rely on preemptive behavior
- The safest way to get predictable, cross-platform results is to use threads that voluntarily relinquish control of the CPU
Example of Threads with Different Priorities
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class CountDownPrioritiesApp {
public static void main(String[] args) {
Thread t0 = new CountDownEven();
Thread t1 = new CountDownOdd();
t0.setPriority(Thread.MIN_PRIORITY);
t1.setPriority(Thread.MAX_PRIORITY);
t0.start();
t1.start();
System.out.println("Main thread done");
}
}
class CountDownEven extends Thread {
public void run() {
for (int i = 10; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
class CountDownOdd extends Thread {
public void run() {
for (int i = 9; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
|
^ top
13.3.5: Thread Pooling
- Thread Pool: a managed collection of threads for performing tasks
- Thread pools are commonly used in multithreaded applications because:
- The overhead of creating and destroying threads is reduced
- The system resources required for the threads is prevented from growing too large
- It makes managing threads easier for the programmer
- JDK 1.5 introduced the concurrency API which includes classes and interfaces for thread pools
- To use the API you need to import the
java.util.concurrent package
import java.util.concurrent.*
To create a thread pool, you can use a factory method of the Executors class
Thread pools in the API implement the ExecutorService interface
Thus, a thread pool is constructed using code like:
ExecutorService tp =
Executors.newFixedThreadPool(2);
Several types of thread pools are available as shown in the table below
One a thread pool is constructed, you add "worker" threads to perform the tasks using the execute() method
Thread t0 = new CountDownEven();
tp.execute(t0);
The execute() method starts the thread which in turn calls the run() method
To stop all the threads in the pool, you use the shutdown() method
tp.shutdown();
The thread pool stops accepting new threads and eventually all the threads complete and the service shuts down
Note that in the example below, you can substitute any of the factory methods and see the different behavior for the type of thread pool
Factory Methods in the Executors Class
Example Using a Fixed-Size Thread Pool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import java.util.concurrent.*;
public class CountDownPoolApp {
public static void main(String[] args) {
ExecutorService tp =
Executors.newFixedThreadPool(2);
Thread t0 = new CountDownEven();
Thread t1 = new CountDownOdd();
Thread t2 = new CountDownEven();
Thread t3 = new CountDownOdd();
tp.execute(t0);
tp.execute(t1);
tp.execute(t2);
tp.execute(t3);
tp.shutdown();
System.out.println("Main thread done");
}
}
class CountDownEven extends Thread {
public void run() {
for (int i = 10; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
class CountDownOdd extends Thread {
public void run() {
for (int i = 9; i > 0; i-= 2) {
System.out.println(getName()
+ " Count: " + i);
Thread.yield();
}
}
}
|
^ top
13.3.6: Summary
- In this section we look at how to make multiple asynchronous threads work together well
- We began by looking at the six states of a thread shown in the Enum Thread.State
- Method
getState() returns one of the six values
- Grouping all the Not Runnable states together, we have a diagram like this:

- You can usually get threads to work together well by making sure they surrender control of the CPU
Thread.yield();
One of the methods to accomplish this is the yield() method
Method yield() pauses the currently executing thread and allows another threads to execute
The thread scheduler is responsible for deciding which thread to run and for how long
You can influence which threads are run by setting their priority
However, you cannot explicitly control which thread is run
If you want one thread to finish before another you can use the join() method
One way to reduce the complexity of managing threads is to use thread pooling
JDK 1.5 introduced the concurrency API which includes classes and interfaces for thread pools
We looked at an example of a thread pool constructed from the API
^ top
Exercise 13.3
Take one minute to prepare an answer to the following questions:
- What state must a thread be in for the thread scheduler to run it?
- What is the difference between the
sleep() and yield() methods
- How do you set the priority of threads?
- How do you make sure threads run cooperatively on multiple platforms?
^ top
13.4: Communicating Between Threads
Objectives
At the end of the lesson the student will be able to:
- Use the
synchronized keyword to control access to critical sections.
- Use the
wait() and notifyAll() methods of the Object class to coordinate the execution of two interdependent threads.
- Describe the producer/consumer pattern used for concurrency control.
|
^ top
13.4.1: About Thread Communication
- So far our threads have run at their own pace without concern for the state or activities of other threads
- These types of threads are known as asynchronous threads
- However, sometimes we need threads to share data
- For example:
- Some threads take orders and some threads process orders
- Some threads put money in accounts and some get money from accounts
- Some threads put keystrokes into a buffer and some get keystrokes from a buffer
- This is known as the producer-consumer pattern
- Within a single JVM, it is common to use shared objects for communication between threads
- Some definitions:
- Buffer: the shared object that stores data
- Producer: the thread that puts data into the buffer
- Consumer: the thread that get data from the buffer

^ top
13.4.2: Example: Producer-Consumer Application
- Let us construct a producer-consumer setup using a shared object
- To keep the example simple, we use an object that stores
int data
- Data is stored in the variable:
private int amount;
We provide access to the variable using a add() and get() methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Buffer {
private int amount;
public void add(int value) {
System.out.print("Adding " + value);
int newAmount = amount + value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
}
public void get(int value) {
System.out.print("Getting " + value);
int newAmount = amount - value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
}
}
|
- To put
int values into the buffer, we code a Producer class
- Each
Producer thread just adds the value ten times
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Producer extends Thread {
private Buffer buf;
private int value;
public Producer(Buffer buffer, int newValue) {
buf = buffer;
value = newValue;
}
public void run() {
try {
for (int i = 0; i < 10; i++) {
buf.add(value);
sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
|
- To remove items from the buffer, we code a
Consumer class
- Each
Consumer thread just removes the value ten times
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Consumer extends Thread {
private Buffer buf;
private int value;
public Consumer(Buffer buffer, int newValue) {
buf = buffer;
value = newValue;
}
public void run() {
try {
for (int i = 0; i < 10; i++) {
buf.get(value);
sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
|
- To manage the application, we code a
ProducerConsumerApp class
- The application first creates the shared buffer object
- Then it creates producer and consumer threads and calls their
start() method
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class ProducerConsumerApp {
public static void main(String[] args) {
Buffer buf = new Buffer();
Thread t0 = new Producer(buf, 12);
Thread t1 = new Consumer(buf, 12);
Thread t2 = new Producer(buf, 12);
Thread t3 = new Consumer(buf, 12);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
|
- What we would expect by running this application is for the amount to vary as values are added and removed
- However, in the end the amount in the buffer should be zero
- Instead, when you run this program repeatedly, you will notice that output is messed up and the final amount is not zero
- Clearly, something incorrect is happening
^ top
13.4.3: Critical Sections
- Critical Section: a piece of code that can only be executed by one thread (or process) at a time
- Sections of code where resources are shared need to be critical sections
- The reason is that a context switch occurs when the program changes which thread is running
- Even the shortest of Java statements have many steps.
- For instance, the Java statement:
i++
- Compiles to bytecode like:
load value
inc
store value
What if a context switch occurs in the middle of this sequence?
Thread 1 Thread 2 Value
load value 0
load value
inc
store value 1
load value
inc
store value 2
inc
store value 1 (corruption!)
This is known as a race condition
In the next section we correct the race conditions in our code
^ top
13.4.4: Creating synchronized Threads
- To prevent data corruption due to race conditions, you must allow only one thread at a time to add or get values
- In other words, we must turn the
add() and get() methods into critical sections
- To accomplish this in Java, you can use the
synchronized keyword in the method declaration
public synchronized void myMethod() {
// statements to execute
}
Thus, to fix our Buffer class we can add the synchronized keyword to both methods:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Buffer {
private int amount;
public synchronized void add(int value) {
System.out.print("Adding " + value);
int newAmount = amount + value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
}
public synchronized void get(int value) {
System.out.print("Getting " + value);
int newAmount = amount - value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
}
}
|
How Synchronization Works
- Every Java object has a mechanism called a lock
- The
synchronized keyword works by giving the lock from an object to a thread
- The first thread to access the method acquires the lock
- When the thread holding the lock finishes the method, the lock is released
- Any other thread attempting to use the method is blocked until the lock is released
- Note that there is only one lock per object
- Thus a lock prevents threads that do not hold the lock from using any synchronized method in the entire object
Synchronizing on Blocks
- Another way to turn a piece of code into a critical section is to synchronize on a block
- Syntax:
synchronized (objectReference) {
// code block
}
Synchronized blocks can use the lock of any object
Thus we can lock the current object using the this keyword:
synchronized (this) {
// code block
}
So another way to fix our Buffer class is with code like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Buffer {
private int amount;
public void add(int value) {
synchronized (this) {
System.out.print("Adding " + value);
int newAmount = amount + value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
}
}
public void get(int value) {
synchronized (this) {
System.out.print("Getting " + value);
int newAmount = amount - value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
}
}
}
|
^ top
13.4.5: Avoiding Deadlock
- Deadlock: A situation where two or more threads are unable to continue because each is waiting for another to do something.
- Lets revisit our producer and consumer activities
- The producer fills the buffer while consumer empties the buffer

- Two problems can arise:
- The producer may try to add to full buffer
- The consumer may try to consume from an empty buffer
- Suppose that we want to disallow the buffer to go negative
- We might be tempted to add code to our
Buffer class like:
public synchronized void get(int value)
throws InterruptedException {
while ((amount - value) < 0) {
Thread.sleep(100);
}
System.out.print("Getting " + value);
int newAmount = amount - value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
}
The problem with sleep() is that it does not release the lock
Now no other method can enter the buffer object and add to the amount
But the get() method is waiting for another thread to add to the amount
This is an example of deadlock
Thus we need some other technique to prevent deadlock while still solving our producer-consumer coordination problems
^ top
13.4.6: Using Signal-Wait Synchronization
- To fix the coordination problems, we use signal-wait synchronization
- What we want is to stop the producer from producing if the buffer is full
- Similarly, the consumer must stop consuming if the buffer is empty
- To implement signal-wait synchronization we use the methods of the
Object class shown in the table below
- Method
wait() will put the current thread in a wait state
- Method
wait() releases the lock, unlike method sleep(), so that other threads can execute synchronized methods
- The effect of the
wait() method is to pause the current thread until it gets woken up
- To wake up a thread in a Waiting state you use either method
notify() or notifyAll()
- Usually, you use the
notifyAll() so that an unusable thread is not chosen by the thread scheduler
- That is also the reason that you usually place the
wait() method in a loop
while (condition) {
wait();
}
Since notifyAll() returns all threads to the Runnable state, each thread must rerun the test condition to determine if it should proceed
If the condition is not correct for the thread, then it should wait again
Note that the wait(), notify() and notifyAll() methods can only be used in synchronized methods
If you call one from an unsynchronized method, you get an IllegalMonitorStateException
Using wait() and notifyAll() does not solve all deadlock problems
There is no known general method to avoid all deadlock situations
Instead, programmers must take care to rigorously prove their threads cannot deadlock
Methods of the Object Class Used for Threading
| Method |
Description |
| wait() |
Causes current thread to wait until another thread invokes the notify() method or the notifyAll() method for the current object. |
| notify() |
Wakes up a single arbitrary thread that is waiting on this object's monitor. |
| notifyAll() |
Wakes up all threads that are waiting on this object's monitor. |
^ top
13.4.7: Example of Signal-Wait Synchronization
- In our
Buffer class, method get() must call wait() when it is empty
while ((amount - value) < 0) {
wait();
}
Then the method add() must call notifyAll() when something is added to the buffer
notifyAll();
This wakes up all the waiting threads so that they can try again
Similarly, method add() must call wait() when it is full
while ((value + amount) > MAX) {
wait();
}
Then method get() must call notifyAll() when it removes something from the buffer
notifyAll();
This wakes up all the waiting threads so that they can try again
The updated Buffer class is shown below
Example Buffer Implementing Signal-Wait Synchronization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class Buffer {
public static final int MAX = 12;
private int amount;
public synchronized void add(int value)
throws InterruptedException {
while ((value + amount) > MAX) {
wait();
}
System.out.print("Adding " + value);
int newAmount = amount + value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
notifyAll();
}
public synchronized void get(int value)
throws InterruptedException {
while ((amount - value) < 0) {
wait();
}
System.out.print("Getting " + value);
int newAmount = amount - value;
System.out.println(", amount=" + newAmount);
amount = newAmount;
notifyAll();
}
}
|
Common Problem
- It is intuitively clear when to call
wait()
- If a thread cannot do its job then it needs to wait
- But when a thread calls
wait() it just goes into a Waiting state and stops trying
- The only way to make the thread runnable again is if another thread calls
notifyAll() (or notify())
- A common error is to have threads wait without matching calls to
notifyAll() by another thread
- Whenever you use
wait(), ask yourself which call to notifyAll() will notify your thread to try again
^ top
13.4.8: Summary
- Sometimes threads need to communicate with each other
- One common way to communicate is by using a shared object
- The producer-consumer pattern is one way for threads to successfully use a shared object
- When resources are shared, some sections of code need to become critical section
- Synchronized methods can be used to ensure that two threads do not run the same method of an object simultaneously
- When a thread calls a synchronized method, the object that contains that method is locked so that it cannot be accessed by another thread
- When threads coordinate with each other, they may get into undesirable states like deadlock
- Deadlock results where two or more threads are unable to continue because each is waiting for another to do something
- You can solve some deadlock problems using the
wait() and notifyAll() methods of Object
- There is no known general method to avoid all deadlock situations
- Instead, programmers must take care to rigorously prove their threads cannot deadlock
^ top
Exercise 13.4
Take one minute to prepare an answer to the following question:
- A lock is associated with of the following?
- A thread
- An object
- A method
- A variable
- Why should you generally use:
while (condition) {
wait();
}
rather than
if (condition) {
wait();
}
^ top
Wrap Up
^ top
Home
| WebCT
| Announcements
| Schedule
| Room Policies
| Course Info
Help
| FAQ's
| HowTo's
| Links
Last Updated: May 21 2005 @20:53:37
|