A Preview of Things to Come |
TheThread.stop
,Thread.suspend
, andThread.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 theThreadDeath
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 ofstop
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
andrun
methods:You can avoid the use ofpublic void start() { blinker = new Thread(this); blinker.start(); } public void stop() { blinker.stop(); // UNSAFE! } public void run() { Thread thisThread = Thread.currentThread(); while (true) { try { thisThread.sleep(interval); } catch (InterruptedException e){ } repaint(); } }Thread.stop
by replacing the applet'sstop
andrun
methods with:public void stop() { blinker = null; } public void run() { Thread thisThread = Thread.currentThread(); while (blinker == thisThread) { try { thisThread.sleep(interval); } catch (InterruptedException e){ } repaint(); } }Thread.suspend
is inherently deadlock-prone so it is also being deprecated, thereby necessitating the deprecation ofThread.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 callingresume
, 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 usingObject.wait
. When the thread is resumed, the target thread is notified usingObject.notify
.For example, suppose your applet contains the following mousePressed event handler, which toggles the state of a thread called
blinker
:You can avoid the use ofPublic void mousePressed(MouseEvent e) { e.consume(); if (threadSuspended) blinker.resume(); else blinker.suspend(); // DEADLOCK-PRONE! threadSuspended = !threadSuspended; }Thread.suspend
andThread.resume
by replacing the event handler above with:and adding the following code to the "run loop":public synchronized void mousePressed(MouseEvent e) { e.consume(); threadSuspended = !threadSuspended; if (!threadSuspended) notify(); }Thesynchronized(this) { while (threadSuspended) wait(); }wait
method throws theInterruptedException
, so it must be inside atry ... catch
clause. It's fine to put it in the same clause as thesleep
. The check should follow (rather than precede) thesleep
so the window is immediately repainted when the the thread is "resumed." The resultingrun
method follows:Note that thepublic void run() { while (true) { try { Thread.currentThread().sleep(interval); synchronized(this) { while (threadSuspended) wait(); } } catch (InterruptedException e){ } repaint(); } }notify
in themousePressed
method and thewait
in therun
method are insidesynchronized
blocks. This is required by the language, and ensures thatwait
andnotify
are properly serialized. In practical terms, this eliminates race conditions that could cause the "suspended" thread to miss anotify
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!
A Preview of Things to Come |