synchronized 原理分析
synchronized 是Java 提供的同步源语,它为 共享资源 提供了原子性 和 可见性保障,本文通过原子性 和 可见性 二个维度分析其实现原理
sync 原子性
通过 monitor 保证 原子性,具体表现为 monitorenter 和 monitorexit 或 ACC_SYNCHRONIZED 来实现加锁
加锁流程如下
锁升级流程
new 对象时,判断 是否开启偏向锁
- 开启偏向锁,构建匿名偏向锁(101)
- 关闭偏向锁,构建无锁对象(001)
- 无锁(001)遇到 线程加锁时,直接加自旋锁/轻量锁(00)
- 偏向锁 遇到 一个线程加锁时,锁状态不变,保存线程ID
- 偏向锁 遇到 多个线程交替加锁时,线程跑到安全点,撤消偏向锁,升级为自旋锁/轻量锁(00)
- 自旋锁 是 每个线程通过CAS指令去更新对象头里面的markword,如果自旋失败次数、或自旋等待时间过长,锁膨胀成重量级锁(10)
- 重量级锁 由 ObjectMonitor 实现,需要由用户态切换到内核态
- 当竞争不激烈时,重量级锁 自动降级为轻量锁
monitorenter 源码分析
CASE(_monitorenter): {
// 获取锁对象
oop lockee = STACK_OBJECT(-1);
// 在线程栈上找到一个空闲的BasicObjectLock对象
BasicObjectLock* limit = istate->monitor_base();
BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base();
BasicObjectLock* entry = NULL;
while (most_recent != limit ) {
if (most_recent->obj() == NULL) entry = most_recent;
else if (most_recent->obj() == lockee) break;
most_recent++;
}
if (entry != NULL) {
// 保存锁对象,表明当前BasicObjectLock持有锁对象lockee
entry->set_obj(lockee);
int success = false;
uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place;
markOop mark = lockee->mark(); // 获取锁对象的头部标记信息
// 获取没有hash值的标记位值,这里为0
intptr_t hash = (intptr_t) markOopDesc::no_hash;
// 判断使用了偏向锁
if (mark->has_bias_pattern()) {
uintptr_t thread_ident;
uintptr_t anticipated_bias_locking_value;
thread_ident = (uintptr_t)istate->thread(); // 获取线程id
anticipated_bias_locking_value =
(((uintptr_t)lockee->klass()->prototype_header() | thread_ident) ^ (uintptr_t)mark) &
~((uintptr_t) markOopDesc::age_mask_in_place);
/* anticipated_bias_locking_value为0,表明还没有批量撤销偏向锁,且当前线程
持有了偏向锁,直接退出 */
if (anticipated_bias_locking_value == 0) {
// already biased towards this thread, nothing to do
if (PrintBiasedLockingStatistics) {
(* BiasedLocking::biased_lock_entry_count_addr())++;
}
success = true;
}
else if ((anticipated_bias_locking_value &
markOopDesc::biased_lock_mask_in_place) != 0) {
/* anticipated_bias_locking_value不为0,可能是批量撤销偏向锁,需要继续判断是否有
线程持有偏向锁,如果其他线程持有偏向锁,判定发生了冲突,就需要撤销偏向锁 */
markOop header = lockee->klass()->prototype_header();
if (hash != markOopDesc::no_hash) {
header = header->copy_set_hash(hash);
}
// CAS将对象头从mark替换为header撤销偏向锁
if (lockee->cas_set_mark(header, mark) == mark) {
if (PrintBiasedLockingStatistics)
(*BiasedLocking::revoked_lock_entry_count_addr())++;
}
}
else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) {
/* 如果anticipated_bias_locking_value不为0,在批量撤销偏向锁时需要更改
epoch的值,这里如果epoch改变了,当前线程需要重偏向 */
markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident);
if (hash != markOopDesc::no_hash) {
new_header = new_header->copy_set_hash(hash);
}
// CAS重偏向
if (lockee->cas_set_mark(new_header, mark) == mark) {
if (PrintBiasedLockingStatistics)
(* BiasedLocking::rebiased_lock_entry_count_addr())++;
}
else {
// CAS失败,发生了竞争,那么进入monitorenter
CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
}
success = true;
}
else {
/* 以上条件均不满足,表明开启了偏向锁,此时偏向锁状态为匿名偏向,尝试CAS
将其偏向为当前线程*/
markOop header = (markOop) ((uintptr_t) mark &
((uintptr_t)markOopDesc::biased_lock_mask_in_place |
(uintptr_t)markOopDesc::age_mask_in_place |
epoch_mask_in_place));
if (hash != markOopDesc::no_hash) {
header = header->copy_set_hash(hash);
}
markOop new_header = (markOop) ((uintptr_t) header | thread_ident);
// CAS重偏向
if (lockee->cas_set_mark(new_header, header) == header) {
if (PrintBiasedLockingStatistics)
(* BiasedLocking::anonymously_biased_lock_entry_count_addr())++;
}
else {
// CAS失败,发生了竞争,那么进入monitorenter
CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry),
handle_exception);
}
success = true;
}
}
// 没有获取到锁,那么进入传统的轻量级锁
if (!success) {
markOop displaced = lockee->mark()->set_unlocked();
entry->lock()->set_displaced_header(displaced);
bool call_vm = UseHeavyMonitors; // 判断是否直接使用重量级锁
/* 如果没有指定直接使用重量级锁,那么通过CAS操作尝试获取轻量级锁,即替换
头部指针,指向entry */
if (call_vm || lockee->cas_set_mark((markOop)entry, displaced) != displaced) {
// 如果失败,可能是当前线程轻量级锁重入,那么判断是否是锁重入
if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits()))
{
// 轻量级锁重入,不需要设置displaced_header信息
entry->lock()->set_displaced_header(NULL);
} else {
// 否则调用monitorenter
CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry),
handle_exception);
}
}
}
UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
} else {
// 如果未找到,设置more_monitors标志位,由解释器分配新的BasicObjectLock并重试
istate->set_msg(more_monitors);
UPDATE_PC_AND_RETURN(0); // Re-execute
}
}
sync 可见性
sync 通过 缓存一致性协议 保证可见性
MESI
M(modified):修改
E(exclusive):独占
S(shared):共享
I(invalid):无效
sync 和 Lock 的区别
使用
- sync 自动加锁、解锁,Lock 需要手动加锁、解锁
功能
- Lock 支持不同的Condition(不同的等待队列),指定唤醒
Lock 可以使用 tryLock 支持超时
- sync锁 不支持超时
Lock 可以使用Lock.lockInterruptibly 响应中断
- 没有获取到 sync锁 的线程处于 Blocked 状态不能响应interrupt中断
- Lock 支持公平锁 和 非公平锁 ,sync 只支持非公平锁
原理
sync 底层由4种不同状态的锁升级实现, Lock 由 AQS(state + CLH)实现,属于乐观锁
- 无锁、偏向锁、轻量锁都属于用户态
- 轻量锁 由CAS实现,属于乐观锁
- 重量级锁由 Monitor 实现,属于悲观锁
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。