美文网首页
关于volatile

关于volatile

作者: 34sir | 来源:发表于2018-02-22 15:31 被阅读23次

建议先看Java内存模型

作用

一个变量被volatile修饰之后即具有两层意义:

  • 一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的
  • 禁止进行指令重排序

是否保证可见性?

可以
老规矩,看一个栗子:

//线程1
boolean canDo = false;
while(!canDo){
    do();
}
 
//线程2
canDo = true;

基于对内存模型的了解做一下简单的分析:
线程2会先copy一份canDo的值到工作内存,修改了值后并没有立即刷新到主存,这时可能出现线程2意外被终止,而线程1看不到canDo的最新值,那么就会陷入死循环,这显然不是我们想要的结果,于是这就出现了volatile的戏份了

canDovolatile修饰后会产生如下的变化:

  • canDo的值修改后会立即刷新到主存
  • 当线程2进行修改时,会导致线程1的工作内存中缓存变量canDo的缓存行无效
  • 线程1再次读取canDo值时,由于缓存行无效会直接从主存读取

上述三点体现出了立即可见

是否保证原子性?

不可以
看栗子:

public volatile int vol = 0;
     
    public void add() {
        vol++;
    }
     
    public  void test() {
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        add();
                };
            }.start();
        }
    }

我们期望的结果是:10*1000,但是结果往往偏小
我们做一下分析:
vol++这种自增操作显然不满足原子性,那么就有可能出现线程1刚将vol值读到工作内存还没执行自增操作,虽然volvolatile所修饰,但主存中它的值依然是100(假设此时值为100),此时线程2已经执行自增操作,所以截止到线程2执行完成vol的值是101,而不是我们期望的两次自增后的102
所以结论是volatile无法保证原子性

如何保证原子性?

三种方式:

  • synchronized
  • Lock
  • AtomicInteger

synchronized方式:

 public synchronized void add() {
        vol++;
    }

Lock方式:

public  void add() {
        lock.lock();
        try {
            vol++;
        } finally{
            lock.unlock();
        }
    }

AtomicInteger方式:

 public  AtomicInteger vol = new AtomicInteger(); //java 1.5中出现的原子操作类
     
    public  void add() {
        vol.getAndIncrement();
    }

这里对AtomicInteger做一下解释:
在java 1.5的java.util.concurrent.atomic包下提供了一些原子操作类,即对基本数据类型的 自增(加1操作),自减(减1操作)、以及加法操作(加一个数),减法操作(减一个数)进行了封装,保证这些操作是原子性操作

是否保证有序性?

答案是,不能确保有序性,但可以一定程度上保证有序性
由上文我们可以知道volatile可以禁止指令重排,那这里就有两层含义:

  • 程序执行到volatile的读或者写操作时,其之前的操作肯定全部完成并且结果对后面的可见,其后面的操作还没开始执行(这里的之前之后是指代码的前后顺序)
  • 访问volatile变量的语句不能前移也不能后移

结合一个栗子来理解:

x=0; //语句1
y=1;//语句2
vol=true; //语句3  vol是volatile变量
x=1; //语句4
y=0; //语句5

语句3不能移到1,2之前也不能移到4,5之后,但是1,2和4,5之间的顺序可以调换

看一个栗子来理解volatile确保有序性的价值:

//线程1:
context = loadContext();   //语句1
inited = true;             //语句2
 
//线程2:
while(!inited ){
  sleep()
}
doSomethingwithconfig(context);

倘若代码中inited不是volatile变量,那么就会存在一个问题:
指令重排后有可能语句2在1之前执行,那么doSomethingwithconfig就有可能在context = loadContext()之前执行,就会出现空指针
如果initedvolatile变量,语句1必定在2之前执行,这样就避免了上述问题

原理

volatile是如何保证可见性和禁止指令重排的?

“观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”

lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

  • 确保指令重排序时不会把其后面的指令排到内存屏障之前,也不会把前面的指令排到内存屏障的后面
  • 强制将对缓存的修改操作立即写入主存
  • 如果是写操作,它会导致其他CPU中对应的缓存行无效

使用场景

由上文我们可知synchronized是可以实现volatile所能实现的功能的,那么volatile对比synchronized有什么不同?
答案:volatile性能要优于synchronized但是无法保证操作的原子性

所以使用volatile需要满足两个条件:

  • 对变量的写操作不依赖于当前值
  • 该变量没有包含在具有其他变量的不变式中

上述两个条件简单的说就是需要保证操作的原子性

开发中常见的使用场景:

  • 上文提到过的状态表计量
  • 单例的double check
class Singleton{
    private volatile static Singleton instance = null;
     
    private Singleton() {
         
    }
     
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized (Singleton.class) {
                if(instance==null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

相关文章

  • JMM之再看看Volatile

    Volatile 具体的可见内存可见性一文中volatile相关的知识。这里只扩充一点,关于volatile的内存...

  • 关于volatile

    建议先看Java内存模型 作用 一个变量被volatile修饰之后即具有两层意义: 一个线程修改了某个变量的值,这...

  • 关于volatile

    并发中的三大特点,volatile的两个语义,分别针对了可见性和有序性 关键字volatile可以说是Java虚拟...

  • 关于volatile

    前言 volatile关键字可以说是JAVA比较难理解的一个关键字了,很多书感觉讲的都不太清楚。这篇博客主要梳理一...

  • 深入浅出java中volatile

    引言 这几天看了几篇关于java的volatile关键字的文章,今天就想总结一下关于volatile的相关知识巩固...

  • 并发编程前传

    前言 以前在学习 C++ 关键字 volatile 的时候,看过阿里数据库大牛何登成关于 volatile 的文章...

  • Volatile面试

    今天面试的时候被一个问题卡主了,就是关于Volatile的问题: Q: 请简单介绍下Volatile这个关键字; ...

  • 你真的了解volatile关键字吗?

    volatile关键字经常在并发编程中使用,其特性是保证可见性以及有序性,但是关于volatile的使用仍然要小心...

  • 看了这篇文章,你还敢说你了解volatile关键字吗?

    volatile关键字经常在并发编程中使用,其特性是保证可见性以及有序性,但是关于volatile的使用仍然要小心...

  • 对volatile的理解

    迄今看到的关于C++ Volatile最完美的一篇技术文章,写的非常好: C/C++ Volatile关键词深度剖...

网友评论

      本文标题:关于volatile

      本文链接:https://www.haomeiwen.com/subject/kzvatftx.html