2. Java并发机制的底层实现原理

2020-02-13  本文已影响0人  星冉子

Volatile

volatile认为是轻量级的synchronized,使用和执行成本更低,不会引起上下文切换和调度;

volatile修饰的变量写操作时的汇编代码会多一条:lock指令,作用:

1. 将当前处理器缓存行数据写回内存;

2. 一个处理器的缓存回写会使其他缓存了该内存地址的数据无效;

缓存一致性协议:每个处理器通过嗅探总线数据来保证数据一致;

需要多个线程区写同一个共享变量,volatile变量是不合适的

synchronized

实现原理:JVM基于进入和退出monitor对象实现,进入前代码经编译后插入monitorenter指令,退出时插入monitorexit指令;

任何对象都有一个monitor,monitorenter和monitorexit是配对的;

锁信息的存储:存储在Java对象头中的mark word中;

锁有4种状态:无锁、偏向锁、轻量级锁、重量级锁,锁只能升级不能降级,是为了提高获得和释放锁的效率;

偏向锁:

引入目的:通常锁由一个线程多次获得,为了减少这种情况下的获得代价;

实现原理:Java对象头的Mark Wod中存储了偏向锁的线程ID和锁状态,存在竞争时才释放锁或者竞争锁;

加锁:线程进入同步块时,将线程ID记录到对象的头中,下次进入只需要检测头信息即可重新获得,没有信息才使用CAS竞争锁;

解锁:退出同步代码块或者有线程竞争时;

关闭:Java默认开启了偏向锁,如果确定程序大多数都处于竞争,可以通过JVM参数关闭偏向锁,这时会进入轻量级锁;

轻量级锁:

加锁:线程将对象的MarkWord复制到线程的栈空间并修改然后写回对象,失败时通过自旋获取锁;

解锁:写回对象的MarkWord,若失败表示锁存在竞争,锁升级为重量级锁,重量级锁时其他线程都是阻塞

锁对比

原子操作

处理器如何实现:

总线锁:处理器操作时锁总线,让其他处理器不能操作;

缓存锁:保证内存的缓存一致(即volatile的缓存一致性);

Java如何实现:锁、CAS(利用处理器的CMPXCHG指令)

CAS的问题及解决:

1. ABA问题;解决:数据加上版本号;Java实现:AtomicStampedReference;

2. 循环时间长开销大;解决:利用处理器的pause指令延迟执行;

3. 只能保证一个共享变量的原子操作;解决:锁或者将多个变量包装到一个变量;Java实现:AtomicReference;

JVM中除了偏向锁,其他锁机制都用到了CAS;

上一篇下一篇

猜你喜欢

热点阅读