五、synchronized

2020-08-16  本文已影响0人  此间有道

多线程访问相同的共享可变的变量时,通常需要使用加锁的方式实现同步,避免竞态条件发生。同步的其中一个特征就是互斥,通过使访问顺序串行化,使得并发结果合法和可预期。synchronized是java的关键字,其通过java的内置锁机制实现多线程同步。

一、synchronized的三种锁形态

synchronized在jdk1.5前只有重量级锁,开销较大。为了应对低竞争的场景在jdk1.5增加了偏向锁和轻量级锁。对象的锁状态通过对象头里的markword标识。


mark word
1. 偏向锁
image.png

1)场景:在一个时刻只有一个线程请求锁,没有竞争;
2)关键参数:
-XX:+UseBiasedLocking # 是否开启偏向锁,jdk1.6以后默认开启
-XX:BiasedLockingStartupDelay=4000 # 偏向锁延迟启动时间,
-XX:BiasedLockingDecayTime=25000 # 重置撤销次数的时间阈值
-XX:BiasedLockingBulkRevokeThreshold=40 # 偏向锁批量撤销阈值
-XX:BiasedLockingBulkRebiasThreshold=20 # 偏向锁批量重偏向阈值

Note:

3)实现原理:markword标识出偏向锁状态,且保存当前持有锁的线程ID。然后在其线程栈上隐式保存递归次数。


image.png

4)优点:在无竞争的情况下开销较小,包括cpu(无须切换上下文和线程调度)和内存(无须分配管程对象)开销。
5)缺点:锁撤销开销较大,需要挂起锁定线程,遍历其线程栈,修改锁记录。甚至比轻量级锁和重量级锁的开销还大。目前HotSpot使用安全点的STW和启发式撤销方法,减少撤销次数,提高性能。
6)可重偏向的条件

Note1: 当类元数据中的epoch与类对象的对象头中的epoch值相等时,表示当前偏向锁有效;否则该偏向锁失效,可重偏向;通过引入epoch减小了重偏向的开销;


image.png

Note2:在调用hashcode时会撤销偏向锁来还原hashcode的占位;
Note3: 调用wait,notify会膨胀为重量级锁。触发管程对象分配和初始化;

2. 轻量级锁(也称为thin lock)
image.png

1)场景:在一段时间内请求的锁的线程较少,且持有锁的线程执行时间短,持有锁的时间短,其他等待线程在有限的自旋等待期可以得到锁。
2)实现结构——栈上锁记录

锁记录在堆栈上分配,在解释执行期间显式分配,或在编译时隐式分配。锁定记录包含一个可以放置移位标记字的位置,以及一个指向被锁定对象的指针。对象指针在分配时由解释器或编译器初始化,当锁被薄锁或胖锁时,移位的标记字被初始化。
from: www.diva-portal.org/smash/get/diva2:754541/FULLTEXT01.pdf

栈上锁记录

3)锁升级过程

当一个线程试图获取一个已经被其他线程持有的轻量级锁(CAS失败)时,非所有者线程将尝试对该锁进行膨胀。在锁膨胀期间,为对象分配和初始化重量级对象监视器结构。膨胀线程将尝试在循环中对锁进行升级,直到成功,或直到其他线程成功地升级锁为止。
from: www.diva-portal.org/smash/get/diva2:754541/FULLTEXT01.pdf

Note1: 调用wait,notify会膨胀为重量级锁。触发管程对象分配和初始化;

3. 重量级锁(也称为fat lock)
image.png

1)管程对象——monitor
通过对象关联的管程对象实现线程阻塞,唤醒机制。其主要依赖操作系统级的互斥量来实现。
2)WaitSet,EntrySet


image.png

3)优点:
在多线程并发激烈的情况下性能表现好,让未获得锁的线程让出时间片和cpu使用权,减少资源消耗。

四、与juc包ReentrantLock对比

ReentrantLock优点:

参考

  1. Java 的偏向锁是怎么实现的? - RednaxelaFX的回答 - 知乎
  2. Evaluating and improving biased locking in the HotSpot virtual machine
  3. https://www.cnblogs.com/LemonFive/p/11248248.html
  4. https://zhuanlan.zhihu.com/p/127884116
上一篇下一篇

猜你喜欢

热点阅读