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