为啥我的布尔变量在停止线程循环时应该是可变的? [复制]

Posted

技术标签:

【中文标题】为啥我的布尔变量在停止线程循环时应该是可变的? [复制]【英文标题】:Why my boolean variable should be volatile while stopping thread loop? [duplicate]为什么我的布尔变量在停止线程循环时应该是可变的? [复制] 【发布时间】:2017-01-26 06:18:59 【问题描述】:

假设我有一个包含 while 循环的线程,我想“从外部”停止它。

public class MyThread extends Thread 

    private boolean running = true;

    @Override
    public void run() 
        while (running) 
            // do something
        
    

    public void setRunning(boolean running) 
        this.running = running;
   

这里是主类:

public class Main 
    public static void main(String[] args) 
        MyThread mt = new MyThread();
        mt.start();
        // do something
        mt.setRunning(false);
    

它似乎可以正常停止,但我已经读过布尔值也应该是易失的。为什么?会加快停车速度吗?

【问题讨论】:

@CKing 等人,我不太确定那个欺骗链接。我也通读了那里的答案。这里的问题是,为什么在实践中它从未真正被认为是必要的。那里的答案和问题并没有很好地解释它,或者根本没有,它们主要是“你应该使用它,因为你应该使用它”。我认为这是一个很好的独特问题。 @JasonC 这是同一个问题以不同的方式提出。任何愿意回答这个问题的人都可以在技术上将他们的答案添加到链接的副本中,因为它们非常密切相关。链接的问题仍然对新答案开放。 OP 可以评论现有答案以获得更多说明。添加一个新问题是 IMO 的懒惰。 @Cking 这也是非常正确的。我想如果这是关闭的(我仍然不会欺骗它),OP 可以在 cmets 中询问其中一些答案。太糟糕了,这个问题的 OP 没有明确表示他们阅读了另一个问题,这个问题当然可以用更有说服力的方式表达。嗯嗯。 【参考方案1】:

当并发线程将缓存运行变量时,这意味着它将缓存在线程工作内存中。

Java 中的 volatile 关键字用作 Java 编译器和线程的指示符,它们不缓存此变量的值并始终从主内存中读取它。因此,如果您想通过实现共享任何读写操作是原子操作的变量,则必须声明为 volatile 变量。

你可以看看下面的图片

【讨论】:

请再看一遍我的例子,告诉我是否理解正确。所以running 变量位于主内存中,当我的线程启动时,run() 函数正在缓存它,对吧?所以当我在并发线程中使用mt.setRunning(false);时,它会直接在主内存中更改running,唯一的问题是在循环中检查它的值时,因为读取时会有延迟?综上所述,我的小程序是SAVING还是READING内存的问题? 是的,你是绝对正确的【参考方案2】:

具有易失性状态将立即在主存储器中更新。所以只要running 更新,并发线程就会立即看到更新的状态。

更新:- 在您的情况下它可以正常工作,可能是因为您没有足够数量的多个线程,或者到那时您已经在主内存中更新了状态。观察这种行为以设置负载测试的最佳方法(使用 Jmeter 等工具)。这表明为什么掌握好理论/基本概念很重要,否则您会在生产环境中遇到这类问题,因为某些项目没有预算/时间表来进行负载测试

【讨论】:

@json c 更新了答案。 请再看一遍我的例子,告诉我是否理解正确。所以running 变量位于主内存中,当我的线程启动时,run() 函数正在缓存它,对吧?所以当我在并发线程中使用mt.setRunning(false);时,它会直接在主内存中更改running,唯一的问题是在循环中检查它的值时,因为读取时会有延迟?综上所述,我的小程序是SAVING还是READING内存的问题?

以上是关于为啥我的布尔变量在停止线程循环时应该是可变的? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何重新启动应用程序的更新循环

ExecutorService线程池中怎么去暂停和继续一个线程

在 C++ 中的线程内启动和停止循环

为啥我的代码停止并且不返回异常?

为啥我的 Java 应用程序没有在每个循环中播放声音?

为啥不应该在函数式编程中使用变量赋值