关于JVM模式对并发结果的影响

怕翻船的忒修斯

起因

昨天听了下关于并发相关的分享,自己就下来写了小demo,想要测试一下,demo如下

import java.util.concurrent.TimeUnit;
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
 Test1 t = new Test1();
        Thread th = new Thread(t);
        th.start();
        TimeUnit.SECONDS.sleep(2);
        t.change();
        System.out.println("has changed");
    }
}
class Test1 implements Runnable {
    private /**volatile*/ boolean flag = true;
    int c = 0;
    @Override
    public void run() {
        while (flag) {
            int a = 1;
            int b = 1;
            c = a + b;
        }
        System.out.println("c: " + c);
        System.out.println("end");
    }
    public void change() {
        this.flag = false;
    }
}

很简答的一个demo,目的是想测试一下加volatile和不加volatile对线程间通讯的影响。感兴趣的小伙伴可以跑一下上面的demo(不加volatile的),看下结果。评论区大家可以留言,看看有没有不同的结果


华丽的分割线*


这里就不卖关子了,按理论来说,上面的demo不加volatile的情况,是会陷入死循环的,程序无法停止。加上volatile以后,由于解决了可见性问题,使得主线程可以读到修改后的flag值,从而使循环停止。
然鹅,神奇的事情发生了,不知道有没有小伙伴和我一样,运行上面的demo发现,诶?程序竟然自己停了....
当时我第一反应是代码写错了,但是让身边的小伙伴看了一下,并运行了一下,和我的结果竟然不一样!他的就没有停止.....

问号
我甚至一度怀疑是我idea的问题(这以后有BUG不能怪我啊,idea出来背锅...)
当我冷静下来,仔细想了想,应该是坏境的问题,排查了一堆有的没的,又上网上查了些资料,最终将眼光放到了JVM上。
通过java -version看了下版本,有了新的发现:我的jvm竟然是32位的,用的竟然是默认的Client模式....又上网查了下JVM不同模式的差别,发现在对代码编译优化上存在差别。
看到这里为了验证一下,我将JVM的模式切换到了Serve进行验证。重新跑了下demo,果然,他停不下来了,疑惑解决。

后续

其实发现是编译器优化导致的问题时,第一反应是前一段时间刚在《Effective java》这本书中提到的一个叫“提升”的优化。为了验证我看了下class反编译以后的文件,结果并没有看到想象中的优化结果......所以这个问题产生的真正原因,目前还没有定位到,后续有时间还有研究研究


最后

感谢大家的时间,欢迎评论区留言写下自己看法,共同交流

阅读 311

talk is cheap,show me the bug

74 声望
36 粉丝
0 条评论

talk is cheap,show me the bug

74 声望
36 粉丝
宣传栏