The Java TM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: To 1.1 -- And Beyond!
Lesson: A Preview of Things to Come

## Threads Changes

> The `Thread.stop`, `Thread.suspend`, and `Thread.resume` methods will be deprecated in the next major release of the JDK.

> `Thread.stop` is being deprecated because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the `ThreadDeath` exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, `ThreadDeath` kills threads silently; thus, the user has no warning that the program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.

> This tutorial has always recommended against using `Thread.stop`. So, hopefully, this change will not affect your programs.

> If however, you 've been using `Thread.stop` in your programs, you should substitute that use with code that provides for a gentler termination. Most uses of `stop` can and should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running.

> For example, suppose your applet contains the following `start`, `stop` and `run` methods:

> >     public void start() {
> >         blinker = new Thread(this);
> >         blinker.start();
> >     }

> >     public void stop() {
> >         blinker.stop();  // UNSAFE!
> >     }

> >     public void run() {
> >         Thread thisThread = Thread.currentThread();
> >         while (true) {
> >             try {
> >     	    Thread.sleep(interval);
> >             } catch (InterruptedException e){
> >             }
> >             repaint();
> >         }
> >     }

> You can avoid the use of `Thread.stop` by replacing the applet's `stop` and `run` methods with:

> >     public void stop() {
> >         blinker = null;
> >     }

> >     public void run() {
> >         Thread thisThread = Thread.currentThread();
> >         while (blinker == thisThread) {
> >             try {
> >     	    Thread.sleep(interval);
> >             } catch (InterruptedException e){
> >             }
> >             repaint();
> >         }
> >     }

> `Thread.suspend` is inherently deadlock-prone so it is also being deprecated, thereby necessitating the deprecation of `Thread.resume`. If the target thread holds a lock on the monitor protecting a critical system resource when it is suspended, no thread can access this resource until the target thread is resumed. If the thread that would resume the target thread attempts to lock this monitor prior to calling `resume`, deadlock results. Such deadlocks typically manifest themselves as "frozen" processes.

> As with `Thread.stop`, the prudent approach is to have the "target thread" poll a variable indicating the desired state of the thread (active or suspended). When the desired state is suspended, the thread waits using `Object.wait`. When the thread is resumed, the target thread is notified using `Object.notify`.

> For example, suppose your applet contains the following mousePressed event handler, which toggles the state of a thread called `blinker`:

> >     Public void mousePressed(MouseEvent e) {
> >         e.consume();

> >         if (threadSuspended)
> >             blinker.resume();
> >         else
> >             blinker.suspend();  // DEADLOCK-PRONE!

> >         threadSuspended = !threadSuspended;
> >     }

> You can avoid the use of `Thread.suspend` and `Thread.resume` by replacing the event handler above with:

> >     public synchronized void mousePressed(MouseEvent e) {
> >         e.consume();

> >         threadSuspended = !threadSuspended;

> >         if (!threadSuspended)
> >             notify();
> >     }

> and adding the following code to the "run loop":

> >     synchronized(this) {
> >         while (threadSuspended)
> >     	wait();
> >     }

> The `wait` method throws the `InterruptedException`, so it must be inside a `try ... catch` clause. It's fine to put it in the same clause as the `sleep`. The check should follow (rather than precede) the `sleep` so the window is immediately repainted when the the thread is "resumed." The resulting `run` method follows:

> >     public void run() {
> >         while (true) {
> >             try {
> >                 Thread.sleep(interval);

> >                 synchronized(this) {
> >                     while (threadSuspended)
> >                         wait();
> >                 }
> >             } catch (InterruptedException e){
> >             }
> >             repaint();
> >         }
> >     }

> Note that the `notify` in the `mousePressed` method and the `wait` in the `run` method are inside `synchronized` blocks. This is required by the language, and ensures that `wait` and `notify` are properly serialized. In practical terms, this eliminates race conditions that could cause the "suspended" thread to miss a `notify` and remain suspended.

> > Note: Don't wait for the next major release of the JDK. These are changes that you can make to improve your programs NOW!

| Start of Tutorial > Start of Trail > Start of Lesson | Search