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 && 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