问题描述:
如果两个线程都对静态共享变量shareVar有引用,其中一个线程1使用 shareVar,另外一个线程2对shareVar进行修改,那么线程1是否能够理解拿到修改后的值呢?
代码描述:
1 | public class StaticVarVisibility { |
程序现象:
如果线程1中循环体内只有i++,此时循环并不会立即停止下来,为什么呢?线程2已经对shareVar设置了false,为什么线程1没有及时获取到修改后的变量呢?
在线程1中无论是循环创建对象还是使用synchronized还是sleep,都会触发线程1对shareVar变量的可见性。
结果分析:
为什么static的变量能够实现可见性?其实跟static是否无关,即使只是一个简单的变量,线程1也是可以读到修改后的数据的,只是时间不可预期而已。
那为什么开始循环没有及时停止呢?原因是在JVM的优化策略下,当线程1频繁使用主存变量shareVar的时候只做use,并未做read-load-use,所以变更后的数据未能及时同步,当执行创建对象、sleep、synchronized这些耗时操作时,cpu对共享变量shareVar的使用不再频繁,所以jvm就可以来保证数据的同步,并从单纯的use变为read-load-use。
当然在shareVar变量前主动加上volatile关键字,程序会立即停下来,因为这相当于告诉jvm当变量进行变更后强制进行read-load-use。
总结:
知晓JVM什么时候只进行use,什么时候进行read-load-use。 在后续的编程中,如果需要修改后的数据必须做到实时可见性,必须在前面添加volatile关键字,这可能在支付相关的业务中存在。