开发者

why thread.stop() doesn't work?

开发者 https://www.devze.com 2023-01-30 11:25 出处:网络
I just learned from sun\'s document that when i invoke thread.stop() method, the run() method will be terminated as the ThreadDeath error thrown out, and also release all the locks this thread holds,

I just learned from sun's document that when i invoke thread.stop() method, the run() method will be terminated as the ThreadDeath error thrown out, and also release all the locks this thread holds, how to prove it?

I tried my test program, shown below:

    public static void main(String[] args) {
  final Object lock = new Object();
  try {
   Thread t = new Thread() {
    public synchronized void run() {
     try {
      synchronized (lock) {
       long start = System.currentTimeMillis();
       for (int i = 0; i < 10000; i++)
        System.out.println("runing.." + i);
       System.out
         .println((System.currentTimeMillis() - start) / 1000);
      }

     } catch (Throwable ex) {
      System.out.println("Caught in run: " + ex);
      ex.printStackTrace();
     }
开发者_如何转开发    }
   };

   t.start();
   // Give t time to get going...
   Thread.sleep(100);
   t.stop(); // EXPECT COMPILER WARNING
  } catch (Throwable t) {
   System.out.println("Caught in main: " + t);
   t.printStackTrace();
  }

 }

Only if i put an wait() in the run() method, then i can catch the ThreadDeath error, does anyone know the details of how jvm handle stop()?

    public static void main(String[] args) {
  final Object lock = new Object();
  try {
   Thread t = new Thread() {
    public synchronized void run() {
     try {
      synchronized (lock) {
       wait();
       long start = System.currentTimeMillis();
       for (int i = 0; i < 10000; i++)
        System.out.println("runing.." + i);
       System.out
         .println((System.currentTimeMillis() - start) / 1000);

      }

     } catch (Throwable ex) {
      System.out.println("Caught in run: " + ex);
      ex.printStackTrace();
     }
    }
   };

   t.start();
   // Give t time to get going...
   Thread.sleep(100);
   t.stop(); // EXPECT COMPILER WARNING
  } catch (Throwable t) {
   System.out.println("Caught in main: " + t);
   t.printStackTrace();
  }

 }


The simple answer is that the jvm has no reliable way to stop a thread. To stop or interrupt a thread, the target thread needs to cooperate by entering some interrupt-able state, such as sleep() or wait().

The Thread.stop() method has been deprecated for this reason (among others). See http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html for more details.


I do not think that I can explain better than Sun.

Here are the quotes from official Javadoc:

Deprecated. This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target threalink textd waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait. For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.

See here: http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html


that is because the thread executes before your current thread comes out of sleep and calls the t.stop.


The Thread.stop() doesn't stop a thread. Instead it call Thread.stop(new ThreadDeath()) which triggers the thread to throw this Error, which is silently ignored by default. i.e. if you throw any other Throwable the uncaughtException will print it to System.err. From ThreadGroup

public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
    parent.uncaughtException(t, e);
} else {
        Thread.UncaughtExceptionHandler ueh = 
            Thread.getDefaultUncaughtExceptionHandler();
        if (ueh != null) {
            ueh.uncaughtException(t, e);
        } else if (!(e instanceof ThreadDeath)) {
    System.err.print("Exception in thread \""
             + t.getName() + "\" ");
            e.printStackTrace(System.err);
        }
    }
}

There is nothing else special/magical about this error. Your thread will unwind in the same manner at it would if you threw new ThreadDeath(). For comparison, try

thread.stop(new RuntimeException());


The explanations about Thread.stop are pretty much right on. The proper way to build a cooperative runnable is as follows:

public class MyRunnable implements Runnable {
    private volatile boolean stopped = false;
    public void stop() {
        stopped = true;
    }

    public void run() {
       // do stuff
       if (stopped) {
         // cleanup and return;
       }

       // do more stuff

       if (stopped) {
           // cleanup and return;
       }
    }
}

Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
r.stop();
t.join(); // if you want to wait for it to die.

OR

public class MyRunnable implements Runnable {
    public void run() {
       // do stuff
       if (Thread.currentThread().isInterrupted()) {
         // cleanup and return;
       }

       // do more stuff

       if (Thread.currentThread().isInterrupted()) {
           // cleanup and return;
       }
    }
}

Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
t.interrupt();
t.join(); // if you want to wait for it to die.

Note that in either case, you have strategic stop points in your code where you're checking to see if you should continue processing. The second approach has the advantage that interrupt aware operations like Thread.sleep and java.nio based I/O operations can be immediately interrupted and don't have to wait for your stop point. Instead they would throw an InterruptedException immediately (or in the case of NIO a ClosedByInterruptException). Note that standard java.io based I/O is not interrupt aware, and you'll have to wait for one of your coded stop points.


The real answer is that the stop method of class Thread calls the private stop1 method which is synchronized. As your implementation of the thread's run method is also synchronized the stop1 method cannot be entered until the run method is exited.

0

精彩评论

暂无评论...
验证码 换一张
取 消