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