Suspending a thread is when we temporarily pause a thread, rather than stop and destroy it. This thread can be resumed at a later stage.
When Java was first introduced threads were a part of the language and worked fine. There were some difficulties
with multi-Platform versions. With the introduction of Java 2 threads were updated to prevent certain race and lock
conditions that occurred. In the 
Thread class there were 
suspend()
and 
resume() methods, but these have been deprecated for JDK1.2+ and so should not be
used - you will get deprecated warnings from the Java compiler if used, and they will lead to unpredictable
threaded code if these warnings are ignored.
Figure 11.3, “A Suspend/Resume Multi-Counter Example” displays a capture of an applet that has suspend/resume functionality on
two separate threads.
CounterApplet.html show this applet
running. Note that the two textfields are controlled by the same buttons, but they are different threads that
start at different points 0 and 50 and count at different rates. The first
one counts every 100ms, whereas the second counts every 200ms (i.e. at half the speed).
The source code is as below and as in
CounterApplet.java.
1
2
3 // A Working Counting Applet - by Derek Molloy
4
5 import java.applet.*;
6 import java.awt.*;
7 import java.awt.event.*;
8
9 public class CounterApplet extends Applet implements ActionListener
10 {
11 private Button start, stop, toggle;
12 private TextField countField1, countField2;
13 private Counter theCounter1, theCounter2;
14
15 public void init()
16 {
17 countField1 = new TextField(10);
18 countField2 = new TextField(10);
19 this.add(countField1);
20 this.add(countField2);
21
22 start = new Button("Start");
23 start.addActionListener(this);
24 this.add(start);
25
26 stop = new Button("Stop");
27 stop.addActionListener(this);
28 this.add(stop);
29
30 toggle = new Button("Toggle");
31 toggle.addActionListener(this);
32 this.add(toggle);
33
34 this.theCounter1 = new Counter(countField1, 100, 0);
35 this.theCounter2 = new Counter(countField2, 200, 50);
36 }
37
38 public void actionPerformed(ActionEvent e)
39 {
40 if (e.getSource().equals(start))
41 {
42 this.theCounter1.start();
43 this.theCounter2.start();
44 }
45 else if (e.getSource().equals(stop))
46 {
47 this.theCounter1.stopCounter();
48 this.theCounter2.stopCounter();
49 }
50 else if (e.getSource().equals(toggle))
51 {
52 this.theCounter1.toggleCounter();
53 this.theCounter2.toggleCounter();
54 }
55 }
56 }
57
58
59
60 class Counter extends Thread
61 {
62 private int count, delay;
63 private boolean running = true, paused = false;
64 private TextField theField;
65
66
67 public Counter(TextField t, int delay, int startValue)
68 {
69 this.theField = t;
70 this.count = startValue;
71 this.delay = delay;
72 }
73
74 public void run()
75 {
76 while (running)
77 {
78 theField.setText("Count: "+this.count++);
79 try
80 {
81 Thread.currentThread().sleep(this.delay);
82
83 synchronized(this) {
84 while (this.paused)
85 wait();
86 }
87 }
88 catch (InterruptedException e)
89 {
90 theField.setText("Interrupted!");
91 this.stopCounter();
92 }
93 }
94 }
95
96 public int getCount() { return count; } // not used in this example
97
98 public void stopCounter() { this.running = false; }
99
100 public synchronized void toggleCounter()
101 {
102 this.paused = !this.paused;
103 if (!this.paused) notify();
104 }
105 }
106
107 I have changed the code from the section called “A Working Counter” to have two separate classes. I did this to
prevent any confusion between the 
Applet class and the thread itself, and to allow for
the creation of two separate thread objects. The 
Applet class creates three buttons as
in Figure 11.3, “A Suspend/Resume Multi-Counter Example” and two 
TextField objects. So how does this code
work?
The 
CounterApplet creates two threads 
theCounter1 that
passes a reference to the 
countField1, sets the counter to 0 and the delay between
counting to 100ms and 
theCounter2 that passes a reference to the 
countField2
and sets the counter to 50 and the delay between counting to 200ms.
The 
actionPerformed() method handles the start button, that calls the

start() method of both 
Counter objects. The "Stop" button
and the "Toggle" button call the 
stopCounter() and 
toggleCounter()
methods of both 
Counter objects.
The 
Counter class extends the 
Thread class and
over-rides the 
run() inherited from 
Thread.
The 
Counter class has a single constructor that requires a

TextField reference, an int delay and an int starting
count value.
There are two boolean states 
running and 
paused.

running is a state that defines if the 
run() method is
looping. The 
paused state defines if the 
wait() is to be
called during the loop.
To stop the counter the 
stopCounter() can be called from outside
the class. The 
stopCounter simply sets the 
running state
to false, so that the next time the loop runs to completion, the while(running)
no longer is true and so the loop ends.
The 
toggleCounter() is a good bit more complex. The idea is
straightforward - when the 
toggleCounter() is called the 
paused
state changes from true to false and then back again the next time
it is called. When the 
paused state is true then the

Thread's 
wait() is called and so the loop pauses at this
very point. In addition, if the 
paused state is true when the
"toggle" button is pressed, then we must un-pause the counter. To do this we must call the Thread's

notify() method to let it know that there has been a change in the states
of the class. We must also use the synchronized modifier on the

wait() and 
notify() methods. This is required
by the language, and ensures that 
wait() and 
notify
are properly serialized. It eliminates race conditions that could cause the "suspended" thread to miss
a notify and remain suspended indefinitely. Rather than place the synchronized on the
entire 
run() method, we have localised it to the 
wait()
method. We will discuss synchronized in the section called “Adding Synchronization to Code”
The 
wait() method (from the 
Object class) causes a thread to release the lock it is
holding on an object - allowing another thread to run. It can only be invoked from within a block of synchronized
code and should be wrapped in a try block as it throws an 
IOException. There are tree
different 
wait() methods:

wait() wait for ever!

wait(long timeout) with a timeout

wait(long timeout, int nanos) with the time measured in nanoseconds
The 
wait() can only be invoked by the thread that currently owns the lock on the object. Once the

wait() is called the thread becomes disabled for scheduling and is dormant until one of the
following things happens:
Some other thread invokes the 
notify() method for this object and the scheduler runs the thread.
Some other thread invokes the 
notifyAll() method for this object and the scheduler runs the thread.
Some other thread interrupts this thread.
If a time was provided, that it has elapsed.
Once one of these things happens the thread then becomes available to the scheduler.
The 
notify() and 
notifyAll() methods are defined in the 
Object class. Like
the 
wait() method, they can only be used within synchronized code. The 
notify() method wakes up a single
thread which is waiting on the object's lock. If there was more than one thread waiting then on the object's lock then the choice of which waiting thread
should be chosen is arbitrary - 
notifyAll() awakens all threads waiting on the object's lock and the scheduler will decide which one
to run. If you call 
notify() on an object with no waiting threads, then the call will just be ignored.
Task: Modify the applet as shown in Figure 11.3, “A Suspend/Resume Multi-Counter Example” to add the following functionality:
Add a new button called Up/Down that when pressed causes the two threaded counters to count the opposite way.
Add a new feature to the 
Counter constructor called maximum, that
allows you to choose a value to count to.
You can see a screen-grab of my solution in Figure 11.4, “My Up/Down Counter Solution” and you can see it running
here - UpDownCounterApplet.html. For
my example I have set the maximum value of each counter to 200. Note that the slower counter will continue to
count until it too reaches 200.
Solution: The solution is here -
UpDownCounterApplet.java but
please do not look at it until you have had a good attempt yourself.
Java has thread scheduling that monitors all running threads in all programs and decides which thread should be running. There are two main type of thread:
Priority Threads - Are regular, user-defined threads.
Daemon Threads - Are low-priority threads (often called service
threads) that provide services to programs, when the load on the CPU is low. The Garbage
Collector Thread is an example of a daemon thread. It is possible for use to convert a user
thread into a daemon thread, or vice-versa, using the 
setDaemon(boolean)

Thread method. If there are only daemon threads running, the scheduler
will exit.
There are two main forms of scheduler: (i) Preemptive that gives a certain time slice to each thread. The scheduler sets up the order that the threads run in. (ii)Non-preemptive that runs a thread until it is complete. Each thread has control of the processor for as long as it requires.
New threads inherit the priority and daemon flag from the thread that created it.
The scheduler decides which thread should be running based on a priority value assigned to the thread. The priority number has a value between 1 and 10 and a thread runs more often if it has a higher priority value. There are three pre-defined priorities:
Thread.MIN_PRIORITY - has the priority value of 1.
Thread.NORM_PRIORITY - Normally a thread has a priority value of 5.
Thread.MAX_PRIORITY - has the priority value of 10.
You can use the 
setPriority() to set the priority level of a thread, so if you
wished to set a 
Thread object called 
testThread to be running
at the highest priority possible, you could call testThread.setPriority(Thread.MAX_PRIORITY);
The method 
getPriority can be used to return the priority level of a given
thread. It returns an int value, as per the list above.
I have written a short example based on the code in the section called “Suspending and Resuming Threads”
to show you the effect of priorities on threads. This example sets the
first 
Counter object to have the maximum priority and the second 
Counter
object to have the minimum priority. The first counter starts with a value of 0 and the second counter starts
with the higher value of 200. I set the delay between counting to be 1ms, in the hope that my machine will not
be able to handle that speed of counting and so will give more priority to the first counter. You can see the
results in Figure 11.5, “Priority Counter Example”, where a screen-grab of this example running shows that the
first counter has caught up with the second counter after ~65526ms, i.e. just over 1 minute. You can also
run it here -
PriorityCounterApplet.html.
The code for this example is below and in
PriorityCounterApplet.java
1
2
3 // A Working Counting Scheduled Applet - by Derek Molloy
4
5 import java.applet.*;
6 import java.awt.*;
7 import java.awt.event.*;
8
9 public class PriorityCounterApplet extends Applet implements ActionListener
10 {
11 private Button start, stop, toggle;
12 private TextField countField1, countField2;
13 private Counter theCounter1, theCounter2;
14
15 public void init()
16 {
17 countField1 = new TextField(10);
18 countField2 = new TextField(10);
19 this.add(countField1);
20 this.add(countField2);
21
22 start = new Button("Start");
23 start.addActionListener(this);
24 this.add(start);
25
26 stop = new Button("Stop");
27 stop.addActionListener(this);
28 this.add(stop);
29
30 toggle = new Button("Toggle");
31 toggle.addActionListener(this);
32 this.add(toggle);
33
34 this.theCounter1 = new Counter(countField1, 0);
35 this.theCounter1.setPriority(Thread.MAX_PRIORITY);
36 this.theCounter2 = new Counter(countField2, 200);
37 this.theCounter2.setPriority(Thread.MIN_PRIORITY);
38 }
39
40 public void actionPerformed(ActionEvent e)
41 {
42 if (e.getSource().equals(start))
43 {
44 this.theCounter1.start();
45 this.theCounter2.start();
46 }
47 else if (e.getSource().equals(stop))
48 {
49 this.theCounter1.stopCounter();
50 this.theCounter2.stopCounter();
51 }
52 else if (e.getSource().equals(toggle))
53 {
54 this.theCounter1.toggleCounter();
55 this.theCounter2.toggleCounter();
56 }
57 }
58 }
59
60
61 class Counter extends Thread
62 {
63 private int count;
64 private boolean running = true, paused = false;
65 private TextField theField;
66
67
68 public Counter(TextField t, int startValue)
69 {
70 this.theField = t;
71 this.count = startValue;
72 }
73
74 public void run()
75 {
76 while (running)
77 {
78 theField.setText("Count: "+this.count++);
79 try
80 {
81 Thread.currentThread().sleep(1);
82
83 synchronized(this) {
84 while (paused)
85 wait();
86 }
87 }
88 catch (InterruptedException e)
89 {
90 theField.setText("Interrupted!");
91 this.stopCounter();
92 }
93 }
94 }
95
96 public int getCount() { return count; }
97
98 public void stopCounter() { this.running = false; }
99
100 public synchronized void toggleCounter()
101 {
102 this.paused = !this.paused;
103 if (!this.paused) notify();
104 }
105 }
106
107
This applet will run at different speeds on different machines. I did not want to give a delay of 0, i.e.

sleep(0) as this would allocate no resources to the system and could lead to
unresponsive buttons and a serious CPU load on your PC - Try it if you like!
© 2006
Dr. Derek Molloy
(DCU).