纸上得来终觉浅,绝知此事要躬行
今天在学习volatile可见性的时候看见一个案例,于是进行编码验证,结果出现了诡异的事件,new了一个线程是改变变量,结果却对主线程可见了,居然跳出了循环。
下面贴出代码
class Test01 {
int num = 0;
public void numTo60() {
this.num = 60;
}
}
public class Test {
public static void main(String[] args) {
Test01 test01 = new Test01();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t commit on");
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
test01.numTo60();
System.out.println("update num to 60 " + test01.num);
}, "AAA").start();
while (test01.num == 0) {
}
System.out.println(Thread.currentThread().getName()+"_get num value to " + "\t" + test01.num);
}
}
测试结果如下
AAA commit on
update num to 60 60
main_get num value to 60
结果非常诡异,明明变量没有加volatile关键字,子线程的修改居然对main线程可见,非常奇怪,于是百度查询,已经问身边的朋友。得到的结果是System.out.println是加synchronized导致的,关于synchronized关键字是是这样解释的
1、获得同步锁;
2、清空工作内存;
3、从主内存拷贝对象副本到工作内存;
4、执行代码(计算或者输出等);
5、刷新主内存数据;
6、释放同步锁。
看到这里大家是否觉得这就是答案了?,但是结果却不是,本人将printLn换成log.info输出也不行,后来干脆什么都不打印。得到的结果依然是跳出循环,
结果还是比较出人意料的。目前楼主还没找到问题的原因,等以后发现问题,会及时更新上出现这个问题的根本原因,所以学习一样东西还是得动手实践才行,网上博客千篇一律,你抄我,我抄你,从理论上来将结果就是阻塞住,但是结果却不是,难道是最新的jvm虚拟机做了优化?