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 底层由4种不同状态的锁降级实现, Lock 由 CAS 实现,属于乐观锁
- 无锁、偏差锁、轻量锁都属于用户态
- 轻量锁 由CAS实现,属于乐观锁
- 重量级锁由 Monitor 实现,属于乐观锁