关于java:如何在没有任何用处的情况下停止永远运行的线程

How to stop a thread that is running forever without any use

在下面的代码中,我有一个while(true)循环。考虑到这样一种情况,在try块中有一些代码,线程应该执行一些大约需要一分钟时间的任务,但是由于一些预期的问题,它一直在运行。我们能停下来吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class thread1 implements Runnable {

    /**
     * @param args
     */

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        thread1 t1 = new thread1();
        t1.run();

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            try{        
                Thread.sleep(10);

            }
            catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}


首先,你不能在这里开始任何线程!您应该创建一个新的线程,并将名称混乱的thread1Runnable传递给它:

1
2
3
thread1 t1 = new thread1();
final Thread thread = new Thread(t1);
thread.start();

现在,当您真正拥有一个线程时,有一个内置的功能可以中断正在运行的线程,称为…interrupt()

1
thread.interrupt();

但是,单独设置此标志没有任何作用,您必须在运行线程中处理此问题:

1
2
3
4
5
6
7
8
9
10
11
while(!Thread.currentThread().isInterrupted()){
    try{        
        Thread.sleep(10);
    }
    catch(InterruptedException e){
        Thread.currentThread().interrupt();
        break; //optional, since the while loop conditional should detect the interrupted state
    }
    catch(Exception e){
        e.printStackTrace();
    }

需要注意的两件事:当线程isInterrupted()时,while循环将结束。但是如果线程在睡眠期间被中断,那么jvm会通过将InterruptedExceptionsleep()中抛出来通知您。抓住它,打破你的循环。就是这样!

其他建议:

  • 关于thread.stop():

Deprecated. This method is inherently unsafe[...]

  • 添加你自己的旗帜并密切关注它是很好的(记住使用AtomicBooleanvolatile)!但是,如果JDK已经为您提供了这样的内置标志,为什么还要麻烦呢?额外的好处是中断sleeps,使线程中断更具响应性。


停止线程的正确方法是对interruptit(stop()已被弃用,可能会产生严重的副作用):

1
t1.interrupt()

这将导致InterruptedExceptionThread.sleep()Object.wait()等方法抛出。

然后只需为这个异常添加一个catch块,并简单地将breakwhile循环中去掉。

编辑:我现在意识到你的无限循环是在主线程中运行的,没有由你的代码创建的线程,它只是run()宁一个Runnable。您需要在某个时刻调用Thread.start(),以生成一个新线程。


将捕获中断移动到循环外部。这不需要更多的代码行,它只是正确地处理中断,即操作被中断。

1
2
3
4
5
6
7
8
9
public void run() {
    try{        
        while(true) {
            Thread.sleep(10);
        }
    } catch(InterruptedException e){
        System.out.println("Thread interrupted"));
    }
}

停止任意线程的唯一方法是中断它。保留对它的引用,然后调用中断方法。


在启动线程之前创建一个设置为true的字段boolean keepGoing,并用while (keepGoing)替换while (true)。在某个时刻,您可以决定在哪里,只需将keepGoing的值更改为false,它就会退出循环。


我建议使用Thread.interrupt()(如@bohemian所述)。与使用特殊标志相比,它有两个优势:

  • 您不需要创建和使用特定于应用程序的API来实现这一点。(中断是保证线程安全的…)

  • Thread.interrupt()将中断在wait()join中被阻塞的线程,或者可能有1个阻塞的I/O调用。

然而,这不是一颗神奇的子弹。如果试图停止的线程正在执行常规代码,则需要定期检查其interrupted()标志,否则它不会停止。这就让我们和船一样,有了一个特别的旗帜机制。线程必须配合,否则无法(安全地)停止。

这是个阴暗的地方。一方面,有一个InterruptedIOException,其javadoc说"表示I/O操作被中断"。另一方面,对于各种java.io流类,javadocs中没有明确提到异常。

确实,某些第三方代码可能无法正确处理interrupted标志,因此中断可能会被"吃掉"。但是如果你有源代码的话,你可以检查一下。这种情况与第三方代码没有太大的不同,第三方代码没有注意您的特别标志机制。

我不建议使用Thread.stop()。基本上是薄片状的。有些人声称这对他们有效,但在我看来,他们要么是在处理一个有效的特殊案件…或者他们很幸运。