博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
01.并发多线程-volatile
阅读量:5874 次
发布时间:2019-06-19

本文共 1810 字,大约阅读时间需要 6 分钟。

可见性

  • 多个线程并发读写一个共享变量的时候,有可能某个线程修改了变量的值,但是其他的线程看不到,也就是对其他线程不可见

工作原理

  • 主要作用是保证可见性以及有序性
  • 不能保证原子性

volatile 怎么保证可见性和有序性

内存可见性
  1. CPU的内存访问很慢,所以CPU有几层的高速缓存,加速内存访问速度
  2. Java的内存模型对上述又进行了一些列的抽象,JMM(java内存模型)规定所有的变量都在存在主内存的,每个线程又包含自己的工作内存
  3. 变量在工作内存中修改以后,就会强制将工作内存中的刷回主内存,主内存的变量值立马变成最新的值
  4. 其余线程中工作内存中的变量缓存直接强制失效过期,不允许直接读取和使用,当线程再次准备使用的时候,会在主内存中直接读取最新的值
有序性
  1. JMM是允许编译器和处理器对指令重排序的,但是规定了as-if-serial语义,即不管怎么重排序,程序的执行结果不能改变
  2. 针对多线程出现的问题,加上volatile 会禁止重排序,可以确保程序的有序性
原子性
  1. volatile虽然不能保证原子性,但是在某一些条件下,还是能提供原子性的
  2. 如读 64 位数据类型,像 long 和 double 都不是原子的,但 volatile 类型的 double 和 long 就是原子的。

底层时间的机制

  • 如果把加入volatile关键字的代码和未加入volatile关键字的代码都生成汇编代码,会发现加入volatile关键字的代码会多出一个lock前缀的指令
  • lock前缀指令实际相当于一个内存屏障
  • 内存屏障提供了一下的功能
    1. 重排序时,不能把后面的指令重排序到内存屏障之前的位置
    2. 使得本CPU的Cacahe写入内存
    3. 写入动作也会引起别的CPU或者别的内核无效化其Cache,相当于让新写入的值对别的线程可见。

应用举例

1. 状态量标记
int a = 0;volatile bool flag = false;public void write() {    a = 2;              //1    flag = true;        //2}public void multiply() {    if (flag) {         //3        int ret = a * a;//4    }}复制代码
2.单例模式的实现,典型的双重检查锁定(DCL)
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;    }}复制代码

这是一种懒汉的单例模式,使用时才创建对象,而且为了避免初始化操作的指令重排序,给instance加上了volatile。

相关的面试题目
1、Java 中能创建 volatile 数组吗?
  • 能,不过创建的是一个指定数组的引用,而不是整个数据,如果改变引用指向的数据,将会受到volatile的保护,但是如果多个线程同时改变数据的元素,volatile标识符就不能祈祷之前的保护作用了
2、volatile 能使得一个非原子操作变成原子操作吗?
  • 一个典型的例子是在类中的有一个long类型的成员变量,如果你知道该成员变量会被多个线程访问,那么最好将这个成员变量设置为volatile,因为java中读取long类型不是院子的,需要分成两步,如果一个线程正在修改该long变量的值,另一个此案城可能只能看到该值的一般(前32为)。但是对一个 volatile 型的 long 或 double 变量的读写是原子。

转载于:https://juejin.im/post/5cfe4975f265da1b8811d1ba

你可能感兴趣的文章
设计模式之简单工厂模式
查看>>
我的Python成长之路---第三天---Python基础(13)---2016年1月16日(雾霾)
查看>>
深度学习-数学-第一篇-标量,向量,矩阵,张量
查看>>
数据库分类
查看>>
How to Read a Book
查看>>
第二讲 线性结构
查看>>
黑盒测试实践进度记录(五)
查看>>
整数的lqp拆分
查看>>
ABP源码分析四十:ZERO的Application和Tenant
查看>>
[论文]Clustering-Based Ensembles as an Alternative to Stacking
查看>>
SVN clean失败解决方法
查看>>
正则判断手机号是不是11位
查看>>
清浮动,防止上下margin重叠(浏览器顶部空白崩溃)
查看>>
2018年终总结
查看>>
StringBuffer与StringBuilder
查看>>
同步、异步、阻塞、非阻塞 简析
查看>>
PYthon常用模块 logging 日志
查看>>
BZOJ1257:[CQOI2007]余数之和(整除分块)
查看>>
[Android]HttpPost之post请求传递Json数据
查看>>
在View页面,使用@if(){ }输出判断正确的内容
查看>>