起因
昨天听了下关于并发相关的分享,自己就下来写了小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反编译以后的文件,结果并没有看到想象中的优化结果......所以这个问题产生的真正原因,目前还没有定位到,后续有时间还有研究研究
最后
感谢大家的时间,欢迎评论区留言写下自己看法,共同交流
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。