Java并发机制的底层实现原理
在多线程并发编程中,volatile和synchronized都扮演者重要角色,volatile是轻量级锁,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改了一个共享变量时,另一个线程能够读到这个修改的值。
如果volatile运用得当,它比synchronized的的使用和执行成本更低,因为它不会引起线程的上下文切换和调度。
volatile
Java语言提供volatile,如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。
实现原理
有volatile变量修饰的共享变量进行写操作的时候会多出一行汇编代码。
|
|
Lock前缀指令在多核处理器下会引发两件事情。
a. 将当前处理器的缓存行数据写回系统的内存
b. 这个写回内存的操作,会使其它CPU里缓存了该内存地址的数据无效
synchronized
重量级锁synchronized实现同步的基础:Java中每一个对象都可以作为锁。
a. 对于普通同步方法,锁是当前的实例对象
b. 对于静态同步方法,锁是当前类的Class对象
c. 对于同步方法块,锁是Synchonized括号里配置的对象
原子操作的实现原理
比较并交换(CAS):CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较旧值有没有发生变化,如果没有发生变化,才交换成新值,否则不交换。
处理器实现原子操作:
a. 通过总线锁保证原子性
b. 使用缓存锁保证原子性
总线锁把CPU和内存之间的通信锁住了,其他处理器不能操作其他的内存地址的数据,开销较大。
用循环CAS实现原子操作
在Java中可以使用锁和循环CAS实现原子操作
JVM中的CAS操作就是利用了处理器提供的CMPXCHG指令实现。自旋CAS实现的基本思路就是循环进行CAS操作直到成功为止。
使用自旋CAS实现的原子操作
|
|
CAS实现原子操作的三大问题
a. ABA问题。从JDK1.5开始,提供AtomicStampedReference来解决问题。这个类的CompareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查版本号是否等于预期版本。
|
|
b. 循环时间长,开销大
c. 只能保证一个共享变量的原子操作。从JDK1.5开始,提供AtomicReference类来保证引用对象之间的原子性,就可以把多个变量塞进一个对象进行原子操作。
比较
锁 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
轻量级锁 | 提高线程响应速度 | 会空旋,消耗CPU | 同步块执行速度快 |
重量级锁 | 提高吞吐量 | 线程阻塞 | 同步块执行速度慢 |