Java并发编程程序员

Java内存模型-volatile内存语义

2018-05-08  本文已影响74人  markfork

章节目录

1.volatile 的特性

首先应该明确的一点是:当声明共享变量为volatile后,对这个变量的读/写(分为单元素读写,与复合写操作)。不同的读写模式下,volatile变量对写操作的原子性体现是不一样的。

理解volatile特性的一个好办法是把对volatile变量的单个读/写,看成是同一个锁对这些单个读/写操作做了同步,示例代码如下所示:

class VolatileFeaturesExample {
   volatile long vl = 0L;
   public void set(long l){
      vl = l;
   }

   public void getAndIncrement() {
       vl++;
   }

  public long get(){
     return vl;
  }
}

假设有多个线程调用上述程序中的3个方法,这个程序语义和下面的程序语义等价

class VolatileFeaturesExample {
   long vl = 0L;
   public  synchronized void set(long l){
      vl = l;
   }

   public void getAndIncrement() {
       long temp = get();
       temp +=1L;
       set(temp);
   }

  public syntronized long get(){
     return vl;
  }
}

解释

volatile 自身特性:

1.内存可见性:对一个volatile变量的读,总能看到任意线程对这个volatile变量
  最后的写入(内存可见性保证)
2.原子性:对任意单个volatile变量的单独的读写操作,都具有原子性。但对于
  volatile++这种复合操作不具有原子性。

2.volatile 写-读建立的 happens-before 关系

JMM基于共享内存模型实现线程之间的通信

从jdk1.5 开始 volatile 变量的写-读可以实现线程之间的通信。

volatile & synchronized内存语义

从内存语义来说,volatile的写-读与锁的释放-获取有相同的内存效果:volatile
写和锁释放有相同的内存语义;volatile读与锁的获取有相同的内存语义。

下面为volatile变量示例代码:

class VolatileExample {
    int a = 0;//其实是线程共享变量
    volatile boolean flag = false;

    public  void writer(){
        a = 1;                   //1
        flag = true;             //2
    }

   public void reader(){
       if(flage){                //3
         int i = a;              //4
         ......
      }
   }
}

假设线程A 执行 writer() 方法之后,线程B 执行reader() 方法。根据happens-before 规则,这个过程建立的happens-before规则可以分为三类:
1.根据程序次序规则,1 happens before 2;3 happens before 4.
2.根据volatile规则,2 happens-before 3
3.根据happens-before c传递性规则 1 happens-before 4

图形化形势如下图所示:

volatile-写-读 happens-before 关系

A线程在写一个volatile变量后,B线程读同一个volatile变量。A线程在写volatile之前所有的可见共享变量,在B线程读到同一个volatile变量之后,将立即变得对B线程可见。

4. volatile 写-读的内存语义

** volatile 写内存语义 **

当写一个volatile变量时,JMM会把该线程对应的本地内存的变量中的变量值强制刷新到主内存。

volatile 读的内存语义

 当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

volatile内存语义 总结

上一篇下一篇

猜你喜欢

热点阅读