1<!doctype html>
2<!--
3 Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
4 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
6 This code is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License version 2 only, as
8 published by the Free Software Foundation.  Oracle designates this
9 particular file as subject to the "Classpath" exception as provided
10 by Oracle in the LICENSE file that accompanied this code.
11
12 This code is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 version 2 for more details (a copy is included in the LICENSE file that
16 accompanied this code).
17
18 You should have received a copy of the GNU General Public License version
19 2 along with this work; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21
22 Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 or visit www.oracle.com if you need additional information or have any
24 questions.
25-->
26<html lang="en">
27<head>
28  <title>Java Thread Primitive Deprecation</title>
29  <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
30</head>
31<body>
32<h2>Java Thread Primitive Deprecation</h2>
33<hr>
34<h3>Why is <code>Thread.stop</code> deprecated?</h3>
35<p>Because it is inherently unsafe. Stopping a thread causes it to
36unlock all the monitors that it has locked. (The monitors are
37unlocked as the <code>ThreadDeath</code> exception propagates up
38the stack.) If any of the objects previously protected by these
39monitors were in an inconsistent state, other threads may now view
40these objects in an inconsistent state. Such objects are said to be
41<i>damaged</i>. When threads operate on damaged objects, arbitrary
42behavior can result. This behavior may be subtle and difficult to
43detect, or it may be pronounced. Unlike other unchecked exceptions,
44<code>ThreadDeath</code> kills threads silently; thus, the user has
45no warning that his program may be corrupted. The corruption can
46manifest itself at any time after the actual damage occurs, even
47hours or days in the future.</p>
48<hr>
49<h3>Couldn't I just catch the <code>ThreadDeath</code> exception
50and fix the damaged object?</h3>
51<p>In theory, perhaps, but it would <em>vastly</em> complicate the
52task of writing correct multithreaded code. The task would be
53nearly insurmountable for two reasons:</p>
54<ol>
55<li>A thread can throw a <code>ThreadDeath</code> exception
56<i>almost anywhere</i>. All synchronized methods and blocks would
57have to be studied in great detail, with this in mind.</li>
58<li>A thread can throw a second <code>ThreadDeath</code> exception
59while cleaning up from the first (in the <code>catch</code> or
60<code>finally</code> clause). Cleanup would have to be repeated till
61it succeeded. The code to ensure this would be quite complex.</li>
62</ol>
63In sum, it just isn't practical.
64<hr>
65<h3>What about <code>Thread.stop(Throwable)</code>?</h3>
66<p>In addition to all of the problems noted above, this method may
67be used to generate exceptions that its target thread is unprepared
68to handle (including checked exceptions that the thread could not
69possibly throw, were it not for this method). For example, the
70following method is behaviorally identical to Java's
71<code>throw</code> operation, but circumvents the compiler's
72attempts to guarantee that the calling method has declared all of
73the checked exceptions that it may throw:</p>
74<pre>
75    static void sneakyThrow(Throwable t) {
76        Thread.currentThread().stop(t);
77    }
78</pre>
79<hr>
80<h3>What should I use instead of <code>Thread.stop</code>?</h3>
81<p>Most uses of <code>stop</code> should be replaced by code that
82simply modifies some variable to indicate that the target thread
83should stop running. The target thread should check this variable
84regularly, and return from its run method in an orderly fashion if
85the variable indicates that it is to stop running. To ensure prompt
86communication of the stop-request, the variable must be
87<code>volatile</code> (or access to the variable must be
88synchronized).</p>
89<p>For example, suppose your applet contains the following
90<code>start</code>, <code>stop</code> and <code>run</code>
91methods:</p>
92<pre>
93    private Thread blinker;
94
95    public void start() {
96        blinker = new Thread(this);
97        blinker.start();
98    }
99
100    public void stop() {
101        blinker.stop();  // UNSAFE!
102    }
103
104    public void run() {
105        while (true) {
106            try {
107                Thread.sleep(interval);
108            } catch (InterruptedException e){
109            }
110            repaint();
111        }
112    }
113</pre>
114You can avoid the use of <code>Thread.stop</code> by replacing the
115applet's <code>stop</code> and <code>run</code> methods with:
116<pre>
117    private volatile Thread blinker;
118
119    public void stop() {
120        blinker = null;
121    }
122
123    public void run() {
124        Thread thisThread = Thread.currentThread();
125        while (blinker == thisThread) {
126            try {
127                Thread.sleep(interval);
128            } catch (InterruptedException e){
129            }
130            repaint();
131        }
132    }
133</pre>
134<hr>
135<h3>How do I stop a thread that waits for long periods (e.g., for
136input)?</h3>
137<p>That's what the <code>Thread.interrupt</code> method is for. The
138same "state based" signaling mechanism shown above can be used, but
139the state change (<code>blinker = null</code>, in the previous
140example) can be followed by a call to
141<code>Thread.interrupt</code>, to interrupt the wait:</p>
142<pre>
143    public void stop() {
144        Thread moribund = waiter;
145        waiter = null;
146        moribund.interrupt();
147    }
148</pre>
149For this technique to work, it's critical that any method that
150catches an interrupt exception and is not prepared to deal with it
151immediately reasserts the exception. We say <em>reasserts</em>
152rather than <em>rethrows</em>, because it is not always possible to
153rethrow the exception. If the method that catches the
154<code>InterruptedException</code> is not declared to throw this
155(checked) exception, then it should "reinterrupt itself" with the
156following incantation:
157<pre>
158    Thread.currentThread().interrupt();
159</pre>
160This ensures that the Thread will reraise the
161<code>InterruptedException</code> as soon as it is able.
162<hr>
163<h3>What if a thread doesn't respond to
164<code>Thread.interrupt</code>?</h3>
165<p>In some cases, you can use application specific tricks. For
166example, if a thread is waiting on a known socket, you can close
167the socket to cause the thread to return immediately.
168Unfortunately, there really isn't any technique that works in
169general. <em>It should be noted that in all situations where a
170waiting thread doesn't respond to <code>Thread.interrupt</code>, it
171wouldn't respond to <code>Thread.stop</code> either.</em> Such
172cases include deliberate denial-of-service attacks, and I/O
173operations for which thread.stop and thread.interrupt do not work
174properly.</p>
175<hr>
176<h3>Why are <code>Thread.suspend</code> and
177<code>Thread.resume</code> deprecated?</h3>
178<p><code>Thread.suspend</code> is inherently deadlock-prone. If the
179target thread holds a lock on the monitor protecting a critical
180system resource when it is suspended, no thread can access this
181resource until the target thread is resumed. If the thread that
182would resume the target thread attempts to lock this monitor prior
183to calling <code>resume</code>, deadlock results. Such deadlocks
184typically manifest themselves as "frozen" processes.</p>
185<hr>
186<h3>What should I use instead of <code>Thread.suspend</code> and
187<code>Thread.resume</code>?</h3>
188<p>As with <code>Thread.stop</code>, the prudent approach is to
189have the "target thread" poll a variable indicating the desired
190state of the thread (active or suspended). When the desired state
191is suspended, the thread waits using <code>Object.wait</code>. When
192the thread is resumed, the target thread is notified using
193<code>Object.notify</code>.</p>
194<p>For example, suppose your applet contains the following
195mousePressed event handler, which toggles the state of a thread
196called <code>blinker</code>:</p>
197<pre>
198    private boolean threadSuspended;
199
200    Public void mousePressed(MouseEvent e) {
201        e.consume();
202
203        if (threadSuspended)
204            blinker.resume();
205        else
206            blinker.suspend();  // DEADLOCK-PRONE!
207
208        threadSuspended = !threadSuspended;
209    }
210</pre>
211You can avoid the use of <code>Thread.suspend</code> and
212<code>Thread.resume</code> by replacing the event handler above
213with:
214<pre>
215    public synchronized void mousePressed(MouseEvent e) {
216        e.consume();
217
218        threadSuspended = !threadSuspended;
219
220        if (!threadSuspended)
221            notify();
222    }
223</pre>
224and adding the following code to the "run loop":
225<pre>
226                synchronized(this) {
227                    while (threadSuspended)
228                        wait();
229                }
230</pre>
231The <code>wait</code> method throws the
232<code>InterruptedException</code>, so it must be inside a <code>try
233... catch</code> clause. It's fine to put it in the same clause as
234the <code>sleep</code>. The check should follow (rather than
235precede) the <code>sleep</code> so the window is immediately
236repainted when the thread is "resumed." The resulting
237<code>run</code> method follows:
238<pre>
239    public void run() {
240        while (true) {
241            try {
242                Thread.sleep(interval);
243
244                synchronized(this) {
245                    while (threadSuspended)
246                        wait();
247                }
248            } catch (InterruptedException e){
249            }
250            repaint();
251        }
252    }
253</pre>
254Note that the <code>notify</code> in the <code>mousePressed</code>
255method and the <code>wait</code> in the <code>run</code> method are
256inside <code>synchronized</code> blocks. This is required by the
257language, and ensures that <code>wait</code> and
258<code>notify</code> are properly serialized. In practical terms,
259this eliminates race conditions that could cause the "suspended"
260thread to miss a <code>notify</code> and remain suspended
261indefinitely.
262<p>While the cost of synchronization in Java is decreasing as the
263platform matures, it will never be free. A simple trick can be used
264to remove the synchronization that we've added to each iteration of
265the "run loop." The synchronized block that was added is replaced
266by a slightly more complex piece of code that enters a synchronized
267block only if the thread has actually been suspended:</p>
268<pre>
269                if (threadSuspended) {
270                    synchronized(this) {
271                        while (threadSuspended)
272                            wait();
273                    }
274                }
275</pre>
276<p>In the absence of explicit synchronization,
277<code>threadSuspended</code> must be made <code>volatile</code> to ensure
278prompt communication of the suspend-request.</p>
279The resulting <code>run</code> method is:
280<pre>
281    private volatile boolean threadSuspended;
282
283    public void run() {
284        while (true) {
285            try {
286                Thread.sleep(interval);
287
288                if (threadSuspended) {
289                    synchronized(this) {
290                        while (threadSuspended)
291                            wait();
292                    }
293                }
294            } catch (InterruptedException e){
295            }
296            repaint();
297        }
298    }
299</pre>
300<hr size="3" noshade="noshade" />
301<h3>Can I combine the two techniques to produce a thread that may
302be safely "stopped" or "suspended"?</h3>
303Yes, it's reasonably straightforward. The one subtlety is that the
304target thread may already be suspended at the time that another
305thread tries to stop it. If the <code>stop</code> method merely sets
306the state variable (<code>blinker</code>) to null, the target thread
307will remain suspended (waiting on the monitor), rather than exiting
308gracefully as it should. If the applet is restarted, multiple
309threads could end up waiting on the monitor at the same time,
310resulting in erratic behavior.
311<p>To rectify this situation, the <code>stop</code> method must ensure
312that the target thread resumes immediately if it is suspended. Once
313the target thread resumes, it must recognize immediately that it
314has been stopped, and exit gracefully. Here's how the resulting
315<code>run</code> and <code>stop</code> methods look:</p>
316<pre>
317    public void run() {
318        Thread thisThread = Thread.currentThread();
319        while (blinker == thisThread) {
320            try {
321                Thread.sleep(interval);
322
323                synchronized(this) {
324                    while (threadSuspended &amp;&amp; blinker==thisThread)
325                        wait();
326                }
327            } catch (InterruptedException e){
328            }
329            repaint();
330        }
331    }
332
333    public synchronized void stop() {
334        blinker = null;
335        notify();
336    }
337</pre>
338If the <code>stop</code> method calls <code>Thread.interrupt</code>, as
339described above, it needn't call <code>notify</code> as well, but it
340still must be synchronized. This ensures that the target thread
341won't miss an interrupt due to a race condition.
342<hr>
343<h3>What about <code>Thread.destroy</code>?</h3>
344<code>Thread.destroy</code> was never implemented and has been
345deprecated. If it were implemented, it would be deadlock-prone in
346the manner of <code>Thread.suspend</code>. (In fact, it is roughly
347equivalent to <code>Thread.suspend</code> without the possibility
348of a subsequent <code>Thread.resume</code>.)
349<hr>
350<h3>Why is <code>Runtime.runFinalizersOnExit</code>
351deprecated?</h3>
352Because it is inherently unsafe. It may result in finalizers being
353called on live objects while other threads are concurrently
354manipulating those objects, resulting in erratic behavior or
355deadlock. While this problem could be prevented if the class whose
356objects are being finalized were coded to "defend against" this
357call, most programmers do <i>not</i> defend against it. They assume
358that an object is dead at the time that its finalizer is called.
359<p>Further, the call is not "thread-safe" in the sense that it sets
360a VM-global flag. This forces <i>every</i> class with a finalizer
361to defend against the finalization of live objects!</p>
362<p><!-- Body text ends here --></p>
363</body>
364</html>
365