关于Java线程并发的一个小问题

发布于 2022-09-03 07:54:21 字数 1006 浏览 39 评论 0

前段时间我在看Effective Java的时候,第10章-并发中有这样一个讲解:

public class StopThread {
    private static boolean stopRequested;
    
    public static void main(String[] args) throws Exception {
        Thread backgroundThread = new Thread(new Runnable(){
            public void run() {
                int i = 0;
                while(!stopRequested) {
                    i++;
                }
            }
        });
        backgroundThread.start();
        
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
    
}

书上说:“你可能期待这个程序运行大约一秒左右,之后主线程将stopRequested设置为true,使后台线程的循环终止。但是在我的机器上,这个程序永远不会终止:因为后台线程永远在循环!问题在于,由于没有同步,就不能保证后台线程何时‘看到’主线程对stopRequested得值所做的改变。没有同步,虚拟机将这个代码:

while(!done)
    i++;
转变成这样:
if(!done)
    while(true)
        i++;

这到底是什么意思呢?为什么没有使用同步则后台线程看不到stopRequested的变化呢?
最主要的问题在于,这段代码在我的机器上跑,貌似1秒就结束了。
没有出现书中说描述的情况。书上这么写的原因是什么呢?为什么写成书上的样子就可以防止可见性问题的出现?

希望各位大神帮忙看下,给小弟我讲解讲解。小弟我是个技术小白。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

执笔绘流年 2022-09-10 07:54:21

在没有使用同步手段的时候,当主线程对stopRequested作的修改时,不能确定backgroundThread什么时候能看到变量更改。
因为在代码执行时,会将变量从内存加载到寄存器,如果没有同步,如果另外一个线程(A)对变量的更改就无法刷新到另一个线程(B)中,因为B使用的是寄存器中的变量。如果使用了同步机制,比如synchonized,或者volitle,变量的更改就会立即同步,这样访问这个变量的多个线程就能理科看到了。
在这里,
刚开始执行时,backgroundThread将stopRequested从内存读到寄存器
这里没有使用同步手段,当main线程对stopRequested更新时,只是更新到内存,backgroundThread取到的还是寄存器中的值,所以不会停止。

素食主义者 2022-09-10 07:54:21
  1. 通过查询资料,确实和楼主说的环境有关系,楼主可以参考:
    Does liveness failure that happened in concurrency exist in java 8

  2. main方法结束了,其它非后台线程不会停止运行(我把和junitTest弄混了)

许你一世情深 2022-09-10 07:54:21

这段程序刚开始执行的时候是主线程线程先执行的,然后才是backgroundThread执行,由于给stopRequested变量赋值的时候,停了一秒,这个时候backgroundThread线程抢到了执行权,可能是这个原因吧 个人就建议 不对勿喷!!!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文