synchronized
底层是通过 monitor
锁实现的,每个对象都会关联一个 monitor
锁
monitor的主要组成部分
- owner 指针:指向持有对象锁的线程。初始时 owner 未空
- 计数器:初始值为 0,当线程加锁成功时,计数器 +1,线程释放锁时 -1
- waitSet: 当调用了 wait方法时,线程会被加入到 waitSet中,当调用 notify, notifyAll唤醒线程后,线程会被加入到 entryList
- entryList: 未获取到锁的线程会被加入到 entryList中
对象头
对象头中的 MarkWord 字段会保留monitor的引用,锁的标志。
锁标记位 | 偏移标记位 | |
---|---|---|
01 | 0 | 无锁 |
01 | 1 | 偏向锁 |
00 | - | 轻量级锁 |
10 | - | 重量级锁 |
11 | - | GC 标记 |
synchronized
加锁过程
当线程执行到被 synchronized
修饰的同步代码块时:
通过对象头中的 monitor 对象的引用,找到对应的 monitor锁对象,如果 owner 引用为空,该线程就会获取锁成功,owner指向该 线程,计数器加 1, 否则加锁失败。
synchronized
支持重入锁
同一个线程,没获取一次锁,计数器就加一,没释放一次锁,计数器减一,当计数器为 0 时,线程释放掉全部的锁,owner 重新被设置为 null。
synchronized
锁升级过程
-
无锁:锁对象被创建时,处于无锁状态
-
偏向锁:此时如果有一个线程来获取锁,就会升级为偏向锁,这样就可以保证当该线程下次再来获取锁时,就避免了加锁和解锁的操作,减少系统开销
-
轻量级锁:如果此时又来了一个线程来竞争锁,偏向锁升级为轻量级锁,未获取到锁的线程会自旋尝试获取锁,而不是阻塞,可以减少不必要的上下文切换
-
重量级锁:如果未获取到锁的线程自旋达到一定次数,或者又有别的线程来竞争锁,此时轻量级锁会升级为重量级锁
状态 条件 意义 无锁 新建锁对象 无锁 → 偏向锁 只有一个线程来获取锁 避免同一个线程再次进入同步代码块加锁和解锁的过程 偏向锁 → 轻量级锁 又来一个线程来获取锁 未获取到线程的锁尝试自旋获取锁,而不是阻塞,减少上下文切换 轻量级锁 → 重量级锁 自旋获取锁失败,或有多个线程来竞争锁