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
  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 about <code>Thread.stop(Throwable)</code>?</h3>
  66 <p>In addition to all of the problems noted above, this method may
  67 be used to generate exceptions that its target thread is unprepared
  68 to handle (including checked exceptions that the thread could not
  69 possibly throw, were it not for this method). For example, the
  70 following method is behaviorally identical to Java's
  71 <code>throw</code> operation, but circumvents the compiler's
  72 attempts to guarantee that the calling method has declared all of
  73 the 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
  82 simply modifies some variable to indicate that the target thread
  83 should stop running. The target thread should check this variable
  84 regularly, and return from its run method in an orderly fashion if
  85 the variable indicates that it is to stop running. To ensure prompt
  86 communication of the stop-request, the variable must be
  87 <code>volatile</code> (or access to the variable must be
  88 synchronized).</p>
  89 <p>For example, suppose your applet contains the following
  90 <code>start</code>, <code>stop</code> and <code>run</code>
  91 methods:</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>
 114 You can avoid the use of <code>Thread.stop</code> by replacing the
 115 applet'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
 136 input)?</h3>
 137 <p>That's what the <code>Thread.interrupt</code> method is for. The
 138 same "state based" signaling mechanism shown above can be used, but
 139 the state change (<code>blinker = null</code>, in the previous
 140 example) 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>
 149 For this technique to work, it's critical that any method that
 150 catches an interrupt exception and is not prepared to deal with it
 151 immediately reasserts the exception. We say <em>reasserts</em>
 152 rather than <em>rethrows</em>, because it is not always possible to
 153 rethrow 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
 156 following incantation:
 157 <pre>
 158     Thread.currentThread().interrupt();
 159 </pre>
 160 This 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
 166 example, if a thread is waiting on a known socket, you can close
 167 the socket to cause the thread to return immediately.
 168 Unfortunately, there really isn't any technique that works in
 169 general. <em>It should be noted that in all situations where a
 170 waiting thread doesn't respond to <code>Thread.interrupt</code>, it
 171 wouldn't respond to <code>Thread.stop</code> either.</em> Such
 172 cases include deliberate denial-of-service attacks, and I/O
 173 operations for which thread.stop and thread.interrupt do not work
 174 properly.</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
 179 target thread holds a lock on the monitor protecting a critical
 180 system resource when it is suspended, no thread can access this
 181 resource until the target thread is resumed. If the thread that
 182 would resume the target thread attempts to lock this monitor prior
 183 to calling <code>resume</code>, deadlock results. Such deadlocks
 184 typically 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
 189 have the "target thread" poll a variable indicating the desired
 190 state of the thread (active or suspended). When the desired state
 191 is suspended, the thread waits using <code>Object.wait</code>. When
 192 the 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
 195 mousePressed event handler, which toggles the state of a thread
 196 called <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>
 211 You can avoid the use of <code>Thread.suspend</code> and
 212 <code>Thread.resume</code> by replacing the event handler above
 213 with:
 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>
 224 and adding the following code to the "run loop":
 225 <pre>
 226                 synchronized(this) {
 227                     while (threadSuspended)
 228                         wait();
 229                 }
 230 </pre>
 231 The <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
 234 the <code>sleep</code>. The check should follow (rather than
 235 precede) the <code>sleep</code> so the window is immediately
 236 repainted 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>
 254 Note that the <code>notify</code> in the <code>mousePressed</code>
 255 method and the <code>wait</code> in the <code>run</code> method are
 256 inside <code>synchronized</code> blocks. This is required by the
 257 language, and ensures that <code>wait</code> and
 258 <code>notify</code> are properly serialized. In practical terms,
 259 this eliminates race conditions that could cause the "suspended"
 260 thread to miss a <code>notify</code> and remain suspended
 261 indefinitely.
 262 <p>While the cost of synchronization in Java is decreasing as the
 263 platform matures, it will never be free. A simple trick can be used
 264 to remove the synchronization that we've added to each iteration of
 265 the "run loop." The synchronized block that was added is replaced
 266 by a slightly more complex piece of code that enters a synchronized
 267 block 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
 278 prompt communication of the suspend-request.</p>
 279 The 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
 302 be safely "stopped" or "suspended"?</h3>
 303 Yes, it's reasonably straightforward. The one subtlety is that the
 304 target thread may already be suspended at the time that another
 305 thread tries to stop it. If the <code>stop</code> method merely sets
 306 the state variable (<code>blinker</code>) to null, the target thread
 307 will remain suspended (waiting on the monitor), rather than exiting
 308 gracefully as it should. If the applet is restarted, multiple
 309 threads could end up waiting on the monitor at the same time,
 310 resulting in erratic behavior.
 311 <p>To rectify this situation, the <code>stop</code> method must ensure
 312 that the target thread resumes immediately if it is suspended. Once
 313 the target thread resumes, it must recognize immediately that it
 314 has 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>
 338 If the <code>stop</code> method calls <code>Thread.interrupt</code>, as
 339 described above, it needn't call <code>notify</code> as well, but it
 340 still must be synchronized. This ensures that the target thread
 341 won'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
 345 deprecated. If it were implemented, it would be deadlock-prone in
 346 the manner of <code>Thread.suspend</code>. (In fact, it is roughly
 347 equivalent to <code>Thread.suspend</code> without the possibility
 348 of a subsequent <code>Thread.resume</code>.)
 349 <hr>
 350 <h3>Why is <code>Runtime.runFinalizersOnExit</code>
 351 deprecated?</h3>
 352 Because it is inherently unsafe. It may result in finalizers being
 353 called on live objects while other threads are concurrently
 354 manipulating those objects, resulting in erratic behavior or
 355 deadlock. While this problem could be prevented if the class whose
 356 objects are being finalized were coded to "defend against" this
 357 call, most programmers do <i>not</i> defend against it. They assume
 358 that 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
 360 a VM-global flag. This forces <i>every</i> class with a finalizer
 361 to defend against the finalization of live objects!</p>
 362 <p><!-- Body text ends here --></p>
 363 </body>
 364 </html>