Java 为什么要同时使用布尔值和中断()来表示线程终止?

Java 为什么要同时使用布尔值和中断()来表示线程终止?,java,multithreading,Java,Multithreading,我在读关于如何结束一个线程的文章,这是我从问题中找到的一个链接 在第一个链接中,他们首先讨论使用volatile变量向线程发送要终止的信号。如果变量的值表示停止(例如,如果它是null),线程应该检查该变量并停止操作。因此,要终止线程,可以将该变量设置为null 然后他们讨论添加中断来帮助处理长时间阻塞的线程。他们给出了下面的stop()方法示例,该方法将volatile变量(water)设置为null,然后还抛出一个中断 public void stop() { Thread mori

我在读关于如何结束一个线程的文章,这是我从问题中找到的一个链接

在第一个链接中,他们首先讨论使用
volatile
变量向线程发送要终止的信号。如果变量的值表示停止(例如,如果它是
null
),线程应该检查该变量并停止操作。因此,要终止线程,可以将该变量设置为
null

然后他们讨论添加中断来帮助处理长时间阻塞的线程。他们给出了下面的stop()方法示例,该方法将volatile变量(water)设置为null,然后还抛出一个中断

public void stop() {
    Thread moribund = waiter;
    waiter = null;
    moribund.interrupt();
}
我只是想知道,为什么你们两个都需要?为什么不只使用interrupt(),然后正确处理它?这对我来说似乎是多余的。

请看这个。 您的线程应该检查
thread.isInterrupted()
状态,例如:

Thread myThread = new Thread()  {
    @Override
    public void run() {
        while (!this.isInterrupted()) {
            System.out.println("I'm working");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //We would like also exit from the thread
                return;
            }
        }
    }
};
当您想要停止线程时,您应该调用

myThread.interrupt();
此外,我们还可以使用静态方法
Thread.interrupt()
,该方法也会检查状态,但之后,该方法会清除状态,您必须再次调用
myThread.interrupt()
,以再次设置状态。但我不建议使用
Thread.interrupted()
方法

这种方法有助于优雅地停止线程

因此,我也不认为有任何理由使用额外的
volatile
变量

与@lexicore的答案一样,通过附加的
volatile
标志可以达到相同的行为,但我认为这是多余的代码。

(一般来说,这篇文章的第一部分,可以说我没有注意问题的细节。请跳到问题中讨论的techspec部分的末尾。)

没有很好的技术理由。这部分是由于人为的限制,部分是由于混淆了api设计

首先考虑应用程序开发人员的优先级是创建解决业务问题的工作代码。彻底学习像这样的低级API会在匆忙完成工作中迷失方向

第二,当你在学习东西时,有一种倾向,就是要达到一个足够好的状态,然后把它留在那里。线程和异常处理之类的内容是被忽视的老话题。中断是本书后面的一个主题,用于对书籍进行线程处理

现在想象一个代码库,由多个技能水平和对细节的关注程度不同的人处理,他们可能会忘记从等待和睡眠中抛出InterruptedException会重置中断标志,或者interrupted与isInterrupted不同,或者InterruptedException也会重置中断标志。如果您有一个捕获IOException的finally块,您可能会错过InterruptedException是IOException的一个子类,并且可能会错过恢复中断标志的机会。也许匆忙中的人们决定见鬼去吧,我不能指望这面被打断的旗帜

是这样吗?没有

  • 手动卷起的标志不能像中断那样帮助短路等待或睡眠

  • Java5并发工具期望任务使用中断来取消。执行者希望提交给他们的任务检查是否有中断,以便优雅地退出。您的任务可能会使用其他组件,如阻塞队列。这个队列需要能够响应中断,使用它的东西需要知道中断。handrolled标志不适用于此,因为Java5类不知道它

必须使用中断,因为您使用的是预期中断的工具,但由于不可管理的技术细节,对标志值没有信心,这将导致此类代码

(rant结束,现在实际响应特定的techspec示例)

好的,请特别看这篇techguide文章。有三件事很突出:

1) 除了缩短睡眠时间外,它根本没有利用干扰。然后它只是压制异常,而不必费心恢复标志或检查它。您可以使用InterruptedException在while循环外捕获它来终止,但这不是它的作用。这似乎是一种奇怪的方式

2) 随着示例的充实,很明显,该标志用于打开和关闭等待。有人可能会用中断来表示,但这不是惯用的。所以这里有一面旗子是可以的

3) 这是techguide中的玩具示例。并非所有Oracle内容都像techspecs或API文档那样具有权威性。有些教程有错误陈述或不完整。这可能是代码如此编写的原因,因为作者认为读者不熟悉中断是如何工作的,最好尽量减少使用。众所周知,技术作家会做出这样的选择


如果我重写它使用中断,我仍然会保留该标志;我将使用中断终止,并使用暂停/恢复功能的标志

@NathanHughes是完全正确的,但我将把他的长篇大论换成几句话:第三方代码

这不仅仅是关于“愚蠢的初级开发人员”,在应用程序生命的某个时刻,您将使用大量的第三方库。这些库不会尊重您关于并发性的假设。有时他们会默默地重置中断标志。使用单独的标志可以解决这个问题

不,你不能摆脱第三方代码,就到此为止。

假设您正在编写一个库,例如ThreadPoolExecutor。库中的一些代码需要处理中断…甚至无条件地重置中断标志。为什么?因为以前的Runnable已经完成,而新的Runnable正在进行中。不幸的是,