Tuesday, December 9, 2008

Suspending, Resuming, and Stopping Threads

Suspending, Resuming, and Stopping Threads

Sometimes, suspending execution of a thread is useful. For example, a separate thread can be used to display the time of day. If the user doesn't want a clock, then its thread can be suspended. Whatever the case, suspending a thread is a simple matter. Once suspended, restarting the thread is also a simple matter.

 

The mechanisms to suspend, stop, and resume threads differ between Java 2 and earlier versions. Although you should use the Java 2 approach for all new code, you still need to understand how these operations were accomplished for earlier Java environments.

 

For example, you may need to update or maintain older, legacy code. You also need to understand why a change was made for Java 2. For these reasons, the next section describes the original way that the execution of a thread was controlled, followed by a section that describes the approach required for Java 2.

Suspending, Resuming, and Stopping Threads Using Java 1.1 and Earlier Prior to Java 2, a program used suspend( ) and resume( ), which are methods defined by Thread, to pause and restart the execution of a thread. They have the form shown below:

 

final void suspend( )

final void resume( )

 

The following program demonstrates these methods:

 

// Using suspend() and resume().

class NewThread implements Runnable {

String name; // name of thread

Thread t;

NewThread(String threadname) {

name = threadname;

t = new Thread(this, name);

System.out.println("New thread: " + t);

t.start(); // Start the thread

}

// This is the entry point for thread.

public void run() {

try {

for(int i = 15; i > 0; i--) {

System.out.println(name + ": " + i);

Thread.sleep(200);

}

} catch (InterruptedException e) {

System.out.println(name + " interrupted.");

}

System.out.println(name + " exiting.");

}

}

class SuspendResume {

public static void main(String args[]) {

NewThread ob1 = new NewThread("One");

NewThread ob2 = new NewThread("Two");

try {

Thread.sleep(1000);

ob1.t.suspend();

System.out.println("Suspending thread One");

Thread.sleep(1000);

ob1.t.resume();

System.out.println("Resuming thread One");

ob2.t.suspend();

System.out.println("Suspending thread Two");

Thread.sleep(1000);

ob2.t.resume();

System.out.println("Resuming thread Two");

} catch (InterruptedException e) {

System.out.println("Main thread Interrupted");

}

// wait for threads to finish

try {

System.out.println("Waiting for threads to finish.");

ob1.t.join();

ob2.t.join();

} catch (InterruptedException e) {

System.out.println("Main thread Interrupted");

}

System.out.println("Main thread exiting.");

}

}

 

Sample output from this program is shown here:

New thread: Thread[One,5,main]

One: 15

New thread: Thread[Two,5,main]

Two: 15

One: 14

Two: 14

One: 13

Two: 13

One: 12

Two: 12

One: 11

Two: 11

Suspending thread One

Two: 10

Two: 9

Two: 8

Two: 7

Two: 6

Resuming thread One

Suspending thread Two

One: 10

One: 9

One: 8

One: 7

One: 6

Resuming thread Two

Waiting for threads to finish.

Two: 5

One: 5

Two: 4

One: 4

Two: 3

One: 3

Two: 2

One: 2

Two: 1

One: 1

Two exiting.

One exiting.

Main thread exiting.

LANGUAGE

The Thread class also defines a method called stop( ) that stops a thread. Its signature is shown here:

 

final void stop( )

 

Once a thread has been stopped, it cannot be restarted using resume( ). Suspending, Resuming, and Stopping Threads Using Java 2 While the suspend( ), resume( ), and stop( ) methods defined by Thread seem to be a perfectly reasonable and convenient approach to managing the execution of threads, they must not be used for new Java programs. Here's why. The suspend( ) method of the Thread class is deprecated in Java 2. This was done because suspend( ) can sometimes cause serious system failures. Assume that a thread has obtained locks on critical data structures. If that thread is suspended at that point, those locks are not relinquished. Other threads that may be waiting for those resources can be deadlocked.

 

The resume( ) method is also deprecated. It does not cause problems, but cannot be used without the suspend( ) method as its counterpart. The stop( ) method of the Thread class, too, is deprecated in Java 2. This was done because this method can sometimes cause serious system failures. Assume that a thread is writing to a critically important data structure and has completed only part of its changes. If that thread is stopped at that point, that data structure might be left in a corrupted state.

 

Because you can't use the suspend( ), resume( ), or stop( ) methods in Java 2 to control a thread, you might be thinking that no way exists to pause, restart, or terminate a thread. But, fortunately, this is not true. Instead, a thread must be designed so that the run( ) method periodically checks to determine whether that thread should suspend, resume, or stop its own execution. Typically, this is accomplished by establishing a flag variable that indicates the execution state of the thread. As long as this flag is set to "running," the run( ) method must continue to let the thread execute. If this variable is set to "suspend," the thread must pause. If it is set to "stop," the thread must terminate.

 

Of course, a variety of ways exist in which to write such code, but the central theme will be the same for all programs.

 

The following example illustrates how the wait( ) and notify( ) methods that are inherited from Object can be used to control the execution of a thread. This example is similar to the program in the previous section. However, the deprecated method calls have been removed. Let us consider the operation of this program.

 

The NewThread class contains a boolean instance variable named suspendFlag, which is used to control the execution of the thread. It is initialized to false by the constructor. The run( ) method contains a synchronized statement block that checks suspendFlag. If that variable is true, the wait( ) method is invoked to suspend the execution of the thread.

 

The mysuspend( ) method sets suspendFlag to true. The myresume( ) method sets suspendFlag to false and invokes notify( ) to wake up the thread. Finally, the main( ) method has been modified to invoke the mysuspend( ) and myresume( ) methods.

 

// Suspending and resuming a thread for Java 2

class NewThread implements Runnable {

String name; // name of thread

Thread t;

boolean suspendFlag;

NewThread(String threadname) {

name = threadname;

t = new Thread(this, name);

System.out.println("New thread: " + t);

suspendFlag = false;

t.start(); // Start the thread

}

// This is the entry point for thread.

public void run() {

try {

for(int i = 15; i > 0; i--) {

System.out.println(name + ": " + i);

Thread.sleep(200);

synchronized(this) {

while(suspendFlag) {

wait();

}

}

}

} catch (InterruptedException e) {

System.out.println(name + " interrupted.");

}

System.out.println(name + " exiting.");

}

void mysuspend() {

suspendFlag = true;

}

synchronized void myresume() {

suspendFlag = false;

notify();

}

}

class SuspendResume {

public static void main(String args[]) {

NewThread ob1 = new NewThread("One");

NewThread ob2 = new NewThread("Two");

try {

Thread.sleep(1000);

ob1.mysuspend();

System.out.println("Suspending thread One");

Thread.sleep(1000);

ob1.myresume();

System.out.println("Resuming thread One");

ob2.mysuspend();

System.out.println("Suspending thread Two");

Thread.sleep(1000);

ob2.myresume();

System.out.println("Resuming thread Two");

} catch (InterruptedException e) {

System.out.println("Main thread Interrupted");

}

// wait for threads to finish

try {

System.out.println("Waiting for threads to finish.");

ob1.t.join();

ob2.t.join();

} catch (InterruptedException e) {

System.out.println("Main thread Interrupted");

}

System.out.println("Main thread exiting.");

}

}

 

The output from this program is identical to that shown in the previous section. Later in this Blog, you will see more examples that use the Java 2 mechanism of thread control. Although this mechanism isn't as "clean" as the old way, nevertheless, it is the way required to ensure that run-time errors don't occur. It is the approach that must be used for all new code.

No comments: