Synchronized 原理
文章目录
-
- Synchronized 的特性
- 加锁的过程
-
- 初始状态(无锁状态):
- 偏向锁状态:
- 轻量级锁状态:
- 重量级锁状态:
- 其他的优化操作
-
- 锁消除
- 锁粗化
Synchronized 的特性
偏向锁(Biased Locking):偏向于第一个获取锁的线程。
- 即是乐观锁,也是悲观锁
- Synchronized 开始使⽤乐观锁策略,当发现锁竞争⽐较频繁的时候,就会⾃动切换成悲观锁策略;
- 即是轻量级锁,也是重量级锁
- 既是自旋锁,也是挂起等待锁
- 当没有竞争时,锁处于无锁状态;
- 当尝试第一次加锁时,锁处于偏向锁状态;
- 当有少量竞争时,锁升级为轻量级锁,轻量级锁通过自旋尝试获取锁;
- 如果轻量级锁的自旋尝试失败多次(竞争激烈)(默认10次),锁会进一步升级为重量级锁,此时竞争锁的线程会被挂起等待,直到锁被释放。
- 互斥锁
- 在任何时刻,只有一个线程可以持有锁。
- 非公平锁
synchronized
是非公平锁。它不保证线程获取锁的顺序,可能会导致某些线程长时间等待。
- 可重入锁
- 同一个线程可以多次获取同一个锁,而不会导致死锁。
synchronized
通过维护一个计数器来记录锁被获取的次数,每次获取锁时计数器加1,每次释放锁时计数器减1,当计数器为0时,锁才真正释放。
加锁的过程
初始状态(无锁状态):
1. 对象的Mark Word中没有存储任何线程ID或锁信息。
偏向锁状态:
2. 当第一个线程尝试获取锁时,JVM会将对象头的Mark Word设置为该线程的ID,表示该锁偏向于该线程。
偏向锁不是真的“加锁”,只是给对象头中做⼀个“偏向锁的标记”,记录这个锁属于哪个线程。
如果后续没有其他线程来竞争该锁,那么就不⽤进⾏其他同步操作了(避免了加锁解锁的开销);
如果后续有其他线程来竞争该锁(刚才已经在锁对象中记录了当前锁属于哪个线程了,很容易识别当前申请锁的线程是不是之前记录的线程),那就取消原来的偏向锁状态,进⼊⼀般的轻量级锁状态。
偏向锁本质上相当于“延迟加锁”,能不加锁就不加锁,尽量来避免不必要的加锁开销。
但是该做的标记还是得做的,否则⽆法区分何时需要真正加锁。
JDK17 中取消了偏向锁。
轻量级锁状态:
3. 当另一个线程尝试获取锁时,JVM会撤销偏向锁,并将锁升级为轻量级锁(自适应的自旋锁&#x