volatile变量在各个线程的工作内存中是不存在一致性问题的(从物理存储角度看,各个线程的工作内存中volatile变量也可以存在不一致的情况,但由于每次使用之前都要先刷新,执行引擎看不到不一致的情况,因此可以认为不存在一致性问题),
但是JAVA里面的运算符操作并非原子操作,这导致volatile变量的运算在并发下一样的不安全
由于volatile变量只能保证可见性,在不符合一下两条规则的运算场景中,我们仍然需要通过枷锁(使用synchoronized、java.util.concurrent中的锁或原子类)来保证原子性
例如:B线程依赖于A线程的配置
Map configOptions; char[] configText; // 此变量必须定义为volatile volatile boolean initialized = false; // 假设以下代码在线程A中执行 // 模拟读取配置信息,当读取完成后,将initialized设置为true,通知其他线程配置可用 configOptions = new HashMap(); configText = readConfigFile(fileName); processConfigOptions(configtext, configOptions); initialized = true; -------------------------------------------------------------------------- // 假设以下代码在线程B中执行 // 等待initialized 为true,代表线程A已经把配置信息初始化完成 while(!initialized) { sleep(); } // 使用线程A中初始化好的配置信息 doSomethingWithConfig();
如果定义 initialized变量时没有使用volatile修饰,就可能会由于指令重排序的优化,导致位于线程A中最后一条代码 “
initialized = true;”被提前执行,可能会放在代码块的第一行执行,这样在B线程使用配置信息的代码就可能出现错误
原文:https://www.cnblogs.com/kukufan/p/14406729.html