简体   繁体   English

为什么thread.stop()不起作用?

[英]why thread.stop() doesn't work?

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? 我刚刚从sun的文档中了解到,当我调用thread.stop()方法时,由于抛出ThreadDeath错误,因此run()方法将终止,并且还释放该线程持有的所有锁,如何证明它?

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()? 仅当我在run()方法中放置一个wait()时,我才能捕获ThreadDeath错误,有人知道jvm如何处理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. 简单的答案是,jvm没有可靠的方法来停止线程。 To stop or interrupt a thread, the target thread needs to cooperate by entering some interrupt-able state, such as sleep() or wait(). 要停止或中断线程,目标线程需要通过进入某些可中断状态(例如sleep()或wait())来进行协作。

The Thread.stop() method has been deprecated for this reason (among others). 出于这个原因,Thread.stop()方法已被弃用(其他原因)。 See http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html for more details. 有关更多详细信息,请参见http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

I do not think that I can explain better than Sun. 我认为我不能比Sun更好地解释。

Here are the quotes from official Javadoc: 以下是官方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). 使用Thread.stop停止线程会导致它解锁所有已锁定的监视器(由于未经检查的ThreadDeath异常会在堆栈中传播,这是自然的结果)。 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. stop的许多用法应由仅修改某些变量以指示目标线程应停止运行的代码代替。 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 threa link text d waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait. 如果目标威胁链接文本 d等待较长时间(例如,在条件变量上),则应使用中断方法来中断等待。 For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?. 有关更多信息,请参见为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?

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

那是因为该线程在您当前的线程退出睡眠并执行t.stop之前执行。

The Thread.stop() doesn't stop a thread. Thread.stop()不会停止线程。 Instead it call Thread.stop(new ThreadDeath()) which triggers the thread to throw this Error, which is silently ignored by default. 而是调用Thread.stop(new ThreadDeath()),该线程触发线程引发此错误,默认情况下将忽略该错误。 ie if you throw any other Throwable the uncaughtException will print it to System.err. 即,如果您抛出任何其他Throwable,则uncaughtException会将其打印到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(). 您的线程将以与抛出新的ThreadDeath()时相同的方式展开。 For comparison, try 为了进行比较,请尝试

thread.stop(new RuntimeException());

The explanations about Thread.stop are pretty much right on. 关于Thread.stop的解释非常正确。 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. 第二种方法的优势在于,可以立即中断诸如Thread.sleep和基于java.nio的I / O操作之类的中断感知操作,而不必等待您的停止点。 Instead they would throw an InterruptedException immediately (or in the case of NIO a ClosedByInterruptException). 相反,它们将立即抛出InterruptedException(或者在NIO的情况下为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. 请注意,基于标准java.io的I / O不支持中断,因此您必须等待编码停止点之一。

The real answer is that the stop method of class Thread calls the private stop1 method which is synchronized. 真正的答案是Thread类的stop方法调用了私有的stop1方法,该方法已同步。 As your implementation of the thread's run method is also synchronized the stop1 method cannot be entered until the run method is exited. 由于线程的run方法的实现也已同步,因此除非退出run方法,否则无法输入stop1方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM