synchronized 底层实现
- synchronized 代码块的底层是通过一对指令 monitorenter 和 monitorexit 配合实现。
- Java 6之前,Monitor依靠操作系统内部的互斥锁实现。这会涉及用户态和内核态的转换,所以是重量级操作。
- 新的 JDK 提供了三种不同的实现:
- 偏斜锁(Biased Locking):
- JVM 利用 CAS 操作(compare and swap)标记同步对象(Mark Word部分)当前所偏向线程的ID,不涉及互斥,以此降低无竞争时的开销。
- 这个设计基于假设:大部分对象在其生命周期中只会被一个线程锁定。
- 可在 JVM 启动时指定参数 “-XX:+UseBiasedLocking” 启用偏斜锁;“-XX:-UseBiasedLocking” 禁用偏斜锁
- 偏斜锁(Biased Locking):
-
- 轻量级锁:
- 轻量级锁的获取也是通过 CAS 操作标记同步对象的Mark Word部分来获取
- 重量级锁
- 轻量级锁:
锁的升级、降级
JVM 会根据检测到的竞争状况的不同,优化 synchronized 的运行机制,自动切换到合适的锁实现。
锁的升级
- 没有竞争时,默认使用偏斜锁
- 前提是已启用偏斜锁。如果偏斜锁被禁用,将尝试获取轻量级锁
- 当某线程试图锁定已偏斜到其它线程的对象时,JVM 会撤销偏斜锁,并切换为轻量级锁
- 注:撤销偏斜锁操作是比较重的行为
- 如果获取轻量级锁失败,则会升级为重量级锁
锁的降级
当 JVM 进入安全点时,会检查是否有闲置的 Monitor;如果有,会尝试对其进行降级
- 安全点:HotSpot JVM 处于 Stop-the-World 暂停(传说中的 STW)
部分源码
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);
}
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) ;
}
注:代码中的“Atomic::cmpxchg_ptr”就是传说中的 CAS(compare and swap)
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
markOop mark = obj->mark();
assert(!mark->has_bias_pattern(), "should not see bias pattern here");
if (mark->is_neutral()) {
// Anticipate successful CAS -- the ST of the displaced mark must
// be visible <= the ST performed by the CAS.
lock->set_displaced_header(mark);
if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
TEVENT (slow_enter: release stacklock) ;
return ;
}
// Fall through to inflate() ...
} else if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
assert(lock != mark->locker(), "must not re-lock the same lock");
assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock");
lock->set_displaced_header(NULL);
return;
}
#if 0
// The following optimization isn't particularly useful.
if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
lock->set_displaced_header (NULL) ;
return ;
}
#endif
// The object header will never be displaced to this lock,
// so it does not matter what the value is, except that it
// must be non-zero to avoid looking like a re-entrant lock,
// and must not look locked either.
lock->set_displaced_header(markOopDesc::unused_mark());
// 锁膨胀
ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
}