Java内存模型(四):volatile变量的特殊规则

为了便于理解的一致性,可以先查看前面的Java内存模型(二)。

volatile变量的两种特性

  1. 内存可见性
    可见性意指当一个线程修改了主内存中的变量的值,这个新值对其他线程而言是立即可以得知的。普通变量不能做到这点。
  2. 禁止指令重排序
    普通变量紧紧能保证在方法的执行过程中,所有依赖变量赋值后结果的地方能取到正确的值(当然多线程环境可能某个方法被多个线程同时执行而有违此点),而不能保证变量赋值的操作顺序与程序代码的执行顺序一致。

volatile变量的特殊规则

定义变量V、W被volatile修饰,线程T会操作变量V和W。下面用浅显的语言解释Java内存模型对其的特殊规则:
- 每次使用前从主内存读取
read、load、use必须顺序整体出现。前一个操作是load时才能use,后一个操作时use时才能load。
- 每次修改后立即同步回主内存
assign、store、write必须顺序整体出现。前一个操作是assign时才能store,后一个操作时store时才能assign。
- 避免指令重排序
如果T对V的use或者assign先于T对W的use或者assign,那么T对V的load或者write必须先于T对W的load或者assign。

性能

  • volatile的读操作性能消耗与普通变量几乎没什么差别,写操作可能会慢些,因为它有更多的规则需要遵循(在本地代码中插入许多内存屏障指令以保证处理器不乱序执行)。
  • 在某些情况下其性能确实要优于锁,但是由于虚拟机对锁实行了许多优化和消除,故难以量化会比锁快多少。

使用场景

根据volatile变量的特性,在不符合下面两个规则的情况下,仍旧需要通过加锁(隐式或者显式)来保证原子性。
1. 运算结果不依赖当前值,或者只有单一线程对变量进行写操作。
单一变量写操作很好理解。至于前半句可以举个栗子:boolean变量只有2个状态,当它的值在true或者false之间变化的时候,由true变false不能是因为它的当前值是false,或者说当前值是true时,下个值是随机的,下次最近赋值可以是true或者false。
2. 不与其他状态变量共同参与不变约束。 例如:

  volatile int i=1,j=2;
  if(i<j){//本线程读取到i、j的值时条件成立
      Thread.sleep(5000);//其他线程修改了i、j的值,使得上面的if不成立,但是下面的代码依旧会执行,这不是我们想要的
      doSomething();
  }

你可能感兴趣的:(中级进阶——线程与并发)