JDK1.6中为了减少获得锁和释放锁带来的性能消耗,引入了偏向锁和轻量级锁。
synchronized的执行过程:
1. 检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁
2. 如果不是,则使用CAS将当前线程的ID替换Mard Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1
3. 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
4. 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁
5. 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
6. 如果自旋成功则依然处于轻量级状态。
7. 如果自旋失败,则升级为重量级锁。
锁 | 加锁 | 解锁 | 优点 | 缺点 | 适用场景 |
偏向锁 | 初始:CAS竞争锁,在对象头和栈帧的锁记录里存储线程ID,并置偏向标志位1 非初始:检查Mark Word是否存放当前线程ID
扫描二维码关注公众号,回复:
3549759 查看本文章
其他线程:产生竞争,引起偏向锁释放 |
条件:其他线程尝试竞争偏向锁 等待全局安全点,暂停拥有偏向锁的线程;如果线程不处于活动状态则设置为无锁状态;否则,将栈中的锁记录和对象头的Mark Word:重新偏向其他线程 or 恢复到无锁 or 标记对象不适合作为偏向锁。 疑问:1)为什么要在全局安全点? 2)继续偏向锁 or 升级轻量锁的时机是什么? |
省掉CAS | 锁竞争时,带来额外的锁撤销 | 只有一个线程访问同步块 |
轻量锁 | 1)将Mark Word复制到栈锁记录,Displaced Mark Word; 2)CAS将MW替换为锁记录的指针; 3)失败则自旋; 4)自旋超过一定限制则修改MW为重量锁(指向重量锁-互斥量的指针),并阻塞 |
1)CAS将DMW替换回对象头; 2)失败则说明已经变为重量锁 |
不会阻塞和唤醒,提高响应速度 | 自旋消耗CPU | 追求响应时间 同步块执行速度非常快 |
重量锁 | 同轻量锁,但获取失败时直接阻塞 | 1)释放锁; 2)唤醒等待的线程; |
不自旋消耗CPU | 线程调度 | 追求吞吐量 同步块执行时间较长 |