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