volatile,synchronized,CAS原子操作 定义及原理
Volatile的定义和实现原理
定义:
java内存模型保证定义为volatile的变量,在所有的线程中看到的这个变量的值是一致的.
原理
volatile 是如何保证可见性的?
被volatile修饰的变量在JIT生成的汇编语言中,会在此变量的写操作上加上lock前缀的指令,此指令在多核处理器下会引发两件事情:
- 将 缓存行中此变量的数据写回内存中
- 保证上一步写回内存的操作回使其他CPU里缓存了改内存地址的数据失效
之所以要以上2步,是 因为CPU不是直接和操作内存,他是操作内部的缓存,内部缓存处理完后,不知道何时会写回内存中,因此需要及时写回内存来保证可见性;之后需要每个处理器通过嗅探在总线上的传播的数据来检查自己的缓存的值是不是过期了,过期则设置为失效状态,下次需要使用到此值的时候,则会从内存中加载到内部缓存中
synchronized的定义和实现原理,锁的存储结构
定义:
锁,实现代码块和方法的同步
原理:
利用synchronized实现锁同步的基础,java中任何对象都可以作为锁,表现为一下三种形式:
- 对于普通同步方法: 锁是当前的实例对象
- 对于静态同步方法: 锁是当前类的Class对象
- 对于同步方法快: 锁是synchronized括号里配置的对象
JVM基于进入和退出Monitor对象来实现方法同步和代码同步通过使用monitorenter和monitorexit指令来实现
任何一个对象都有一个monitor与之关联,当一个monitor被持有后,它的对象将处于锁定状态.当执行到monitorenter指令时,将会参数获取对象对应的monitor的所有权.
java 对象的对象头中存储了锁的结构,最新的java中将锁按严重程度分为4种:
-
无锁
-
偏向锁
此锁,说白了就仅适合只有一个线程访问同步块场景的时候,当有多个线程竞争的时候则会升级为轻量级锁
-
轻量级锁
通过CAS竞争来获取锁,线程不会阻塞,提高了程序的响应速度,但是会消耗CPU
-
重量级锁
线程竞争不使用自旋,不会消耗CPU,但是线程阻塞,响应时间缓慢
以上4种状态可升不可降,为的是效率
CAS
定义:
CAS(compare and swap )操作需要输入2个值,一个旧值,一个新值;
在操作期间先比较旧值有没有变化,如果没有变化才交换新值,发生了变化则不交换
java主要是通过锁和循环CAS来实现原子操作
CAS实现原子操作的三大问题:
- ABA问题,既 如果原来的值是A,后来修改成B ,又修改为A 那么其实已经发送了变化,使用CAS时候发现没有变化
- 循环时间长,开销大
- 只能保证一个共享变量的原子操作