Volatile关键字详解

2019-09-26  本文已影响0人  viankoo

基本概念

Java 内存模型中的可见性、原子性和有序性。

Volatile原理

volatile变量是用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制。


当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。

而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。

volatile 性能:

volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

Volatile适用场景

volatile boolean shutdownRequested;
...
public void shutdown() { 
    shutdownRequested = true; 
}

public void doWork() { 
    while (!shutdownRequested) { 
        // do stuff
    }
}

线程1执行doWork()的过程中,可能有另外的线程2调用了shutdown,所以boolean变量必须是volatile。

 //注意volatile!!!!!!!!!!!!!!!!!    
 private volatile static Singleton instace;     

 public static Singleton getInstance(){     
     //第一次null检查       
     if(instance == null){              
        synchronized(Singleton.class) {    //1       
             //第二次null检查         
            if(instance == null){          //2    
               instance = new Singleton(); //3    
            }    
     }             
  }    
  return instance;  

如果不用volatile,则因为内存模型允许所谓的“无序写入”,可能导致失败。——某个线程可能会获得一个未完全初始化的实例。

提醒

volatile不能用于安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个(读取-修改-写入)操作序列组成的组合操作,必须以原子方式执行,而volatile不能提供原子性。

上一篇 下一篇

猜你喜欢

热点阅读