话不多说,先上代码
class Hero{
int num = 0;
public void addNum(){
this.num = 100;
}
}
public class VolatileTest {
public static void main(String[] args) {
Hero hero = new Hero();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"mission start...");
//睡眠3秒
try {
TimeUnit.SECONDS.sleep(3);
hero.addNum();
System.out.println(Thread.currentThread().getName()+"update mission :update my num:"+hero.num);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
},"AAA").start();
//第二个线程,main线程,(理想情况下,上面调用过addNum后,num=100,就不会执行while循环
while(hero.num==0){
System.out.println("我是天才");
}
System.out.println(Thread.currentThread().getName()+" mission success...miannum"+hero.num);
}
}
写这段程序的原本目的是为了测试jvm提供的轻量级的同步机制–volatile的性质:
1.保证可见性
2.不保证原子性
3.禁止指令重排
在写代码的时候为了满足自己,将while循环体加上了print输出语句;
原本预想的结果是:不加volatile修饰,无法保证可见性,num ==0,while循环一直输出“
我是天才
”,可结果是,线程sleep三秒后,就输出了“mission over”任务结束;
这中间到底发生了如何诡异的事情,有什么不可告人的秘密,让我们重新回到那个令人疑惑的代码块上
while(hero.num==0){
System.out.println("我是天才");
}
为了进一步探究如何发生这般诡异离奇,令人疑惑的事情,我决定不畏艰险,放手一搏,于是乎,左手Ctrl右手鼠标左键,进入了println这个诡异的地方:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
哦豁,是不是有种“初极狭,才通人。复行数十步,豁然开朗”的感觉,想必大家看到这里就明白了,其实并没有什么诡异莫测,匪夷所思,怪诞诡奇的地方,有的只是
一个synchronized同步代码块,在我们使用prinln的时候,会在底层进入synchronized代码块,这期间,就会和主内存的变量保持一致,从而也实现了可见性
。看到了结果,是不是觉得很简单。
从这件事上,我们知道,任何事情,不论看起来如何诡异,只要怀揣着一颗发现的心,深入探究,问题有时其实很简单。
版权声明:本文为beArrow原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。