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;

}

// …

}

这就是简单的锁的实现

发表评论

邮箱地址不会被公开。 必填项已用*标注