说起并发的底层,不得不提volatile,CAS,AQS,本文就是揭露它们神秘的面纱
一.volatile
为了更好的理解volatile,我们需要知道以下几个概念
JMM (java内存模型)
- 抽象的概念,并不真实存在,它描述的是一组规则或者规范
- 规定了内存主要划分为主内存和工作内存 (与JVM是不同层面的划分)
- (可以泛泛的理解为主内存就是堆,工作内存就是栈。堆:线程共享 栈:线程独有)
关于不同的线程操作共享资源的步骤如下:
比如 i++
- 将主内存的数据读到(拷贝)工作内存中
- 在工作内存中进行计算:+1
- 刷新主内存(将工作内存最新的值写入到主内存中)
并发的三大特征: (按照上图解释)
- 可见性:(及时通知)一个线程改变共享数据后,刷新到主内存中,保证其他的线程马上知道
- 原子性:不可分离的最小单位。要么一起成功,要么一起失败。 (比如A线程正在执行,这个过程不允许其他线程插入) (比如上面不同的线程操作共享数据的3个步骤,就不保证一气呵成,导致写覆盖)
- 有序性:(避免指令重排)程序执行的顺序按照代码的先后顺序执行
有了前面的知识,我们来谈谈对volatile的理解?
- volatile是java虚拟机提供的轻量级的同步机制。可以用在成员变量上,修饰共享资源
- 保证可见性,有序性(避免指令重排),但是不保证原子性
关于避免指令重排?
- 所谓的指令重排就是代码在编译期间进行优化,可能有些代码的执行流程不是按照我们写的顺序执行的。
- 避免指令重排是操作系统级别的方法,通过一个内存屏障,保证不进行指令重排
如何解决volatile不保证原子性?
- 使用java提供的原子性操作的对象:java.util.concurrent.atomic下的对象
- 这类对象就是基本数据类型的原子性操作
为啥不用synchronized?
- 效率低,杀鸡不用屠龙刀。不至于。
开发中什么时候用到volatile?
- 单例模式的其中一种写法(关于单例模式,专门总结)
- atomic的源码