昨天群友提了一个问题代码如下:
public class mytest {
Integer a = 0;
public static void main(String[] args) throws InterruptedException {
mytest test = new mytest();
test.testVisibility();
}
public void testVisibility() {
new Thread(() -> {
System.out.println("thread 1 start ======= a =" + this.a);
while (this.a != 10) {
}
System.out.println("thred 1 a =======" + this.a);
System.out.println("thread 1 end =======");
}).start();
try {
Thread.sleep(1000);
// TimeUnit.NANOSECONDS.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
}).start();
}
}
根据我认知的内存可见性,中间的睡眠是为了保证线程能先启动并先进入while循环,线程二随后启动修改a的值,线程一先拿到a的副本放到本地工作内存中,并没有去主存中刷新a的值一直是0,而线程二修改a的值为10之后刷新到主存中,线程一看不到所以程序不会暂停。
我第二次把中间的sleep注释掉,那么线程一就能顺利的结束,我又多次调整睡眠的时间大小(我本机windows10 大于1个毫秒就无法正常结束,群友测试1纳秒的时候会时好时坏)的情况。
最终大概得出一个可以接受的结论:
进入while循环后,并不是说就不刷新主存了,cpu偶尔也会去刷新一下主存,这样的等待时间对我们来说是非常短暂的,但对于高速的cpu来说是漫长的,如果线程一进入while,不停的再去主存中刷新a的值,他的值一直都是0,那么如果超过一定次数或者时间cpu会不会对这种情况进行优化呢?我猜是有可能的。所以才会出现这种情况。
顺便还有一点如果在线程一种 while中调用同步方法的时候,共享变量也是会主动去主存中刷新的。所以线程一种如果while中加入了print()方法,那么程序就能正常结束了。
特此记录一下。
结论影响内存可见性的是
Thread.sleep ,println 都会影响到 《《当前》》 线程 将副本与主存同步