Synchronized的底层实现和升级降级
synchronized的代码块是一对 monitorenter/monitorexit指令实现的,Monitor是其中的同步的基本实现单元
之前Monitor完全利用的系统自带的互斥锁,但是需要态之间的切换,所以很重量级
现在的JVM中对于Synchronized进行了改进,提供了多种不同的实现,分别是偏斜锁 轻量级锁 重量级锁
并对于不同的情况,合理实现了锁的升级和降级
在默认情况下,使用编写锁,利用CAS设置Mark Word的线程ID,保证线程获取的优先级
然后其他线程试图获取的时候,JVM就撤销偏斜锁,换为轻量级锁,轻量级锁利用CAS获取锁,然后保存为轻量级锁,
最后就是升级为重量级的锁
在锁的降级中,JVM在安全点中,会进行锁的降级
这一部分,我们展开讲解一些关于synchronized的底层实现
关于Synchronized的运行式.则可能是解释模式,也可能是编译模式的
对于不同的模式,实现的方式不同
对于基类的实现
synchronized的行为是JVM的一部分,我们先锁定monitor_enter 或者Monitor Enter
对于synchronized的主要逻辑
Handle h_obj(THREAD, obj);
if (UseBiasedLocking) {
// Retry fast entry if bias is revoked to avoid unnecessary inflation
ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK);
} else {
ObjectSynchronizer::slow_enter(h_obj, lock, CHECK);
}
UseBiasedLocking是JVM的一个参数,指定是否开启偏移锁
-XX:-UseBiasedLocking
上面是开启的参数
fast_enter是熟悉的获取锁的路径
slow_enter是绕过偏移锁,进入轻量级锁获取逻辑
对fast_ennter的实现是如下的一部分
void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock,
bool attempt_rebias, TRAPS) { if (UseBiasedLocking) { if (!SafepointSynchronize::is_at_safepoint()) { BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD); if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) { return; } } else { assert(!attempt_rebias, “can not rebias toward VM thread”); BiasedLocking::revoke_at_safepoint(obj); } assert(!obj->mark()->has_bias_pattern(), “biases should be revoked by now”); } slow_enter(obj, lock, THREAD); } |
在上面,二次校验了是否开启了偏移锁
然后如果获取不到,只会进入slow_enter
biasedLocking定义了偏移锁相关的操作,revoke_at_safepoint定义了安全点的处理操作
这一部分其实本质上就是设置对象头里面的Mark Word
然后是升级到轻量级锁的实现
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
markOop mark = obj->mark(); if (mark->is_neutral()) { // 将目前的Mark Word复制到Displaced Header上 lock->set_displaced_header(mark); // 利用CAS设置对象的Mark Word if (mark == obj()->cas_set_mark((markOop) lock, mark)) { TEVENT(slow_enter: release stacklock); return; } // 检查存在竞争 } else if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) { // 清除 lock->set_displaced_header(NULL); return; } // 重置Displaced Header lock->set_displaced_header(markOopDesc::unused_mark()); ObjectSynchronizer::inflate(THREAD, obj(), inflate_cause_monitor_enter)->enter(THREAD); } |
首先设置Displaced Header 利用cas_set_mark 设置对象Mark Work,不行就进行锁膨胀
在inflate方法
然后是关于Java锁 api类中的其他实现
类图如下
这些锁主要归为了
可重入锁
不可重入锁
读写锁
读写锁分为了读锁,读锁的原理读操作是不互斥的,不进行干扰,写操作导致并发一致性的竞争,所以需要进行互斥
public class RWSample {
private final Map<String, String> m = new TreeMap<>(); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); public String get(String key) { r.lock(); System.out.println(“读锁锁定!”); try { return m.get(key); } finally { r.unlock(); } } public String put(String key, String entry) { w.lock(); System.out.println(“写锁锁定!”); try { return m.put(key, entry); } finally { w.unlock(); } } // … } |
后期提供了StampedLock,类似读写锁的锁,还能优化读锁,而且可以利用validate 方法确认是否进入了写模式,进入了就获取读锁
public class StampedSample {
private final StampedLock sl = new StampedLock(); void mutate() { long stamp = sl.writeLock(); try { write(); } finally { sl.unlockWrite(stamp); } } Data access() { long stamp = sl.tryOptimisticRead(); Data data = read(); if (!sl.validate(stamp)) { stamp = sl.readLock(); try { data = read(); } finally { sl.unlockRead(stamp); } } return data; } // … } |
这就是简单的锁的实现