本文为死磕Synchronized底层实现第三篇文章,内容为重量级锁实现。

本系列文章将对HotSpot的synchronized锁实现进行全面分析,内容包括偏向锁、轻量级锁、重量级锁的加锁、解锁、锁升级流程的原理及源码分析,希望给在研究synchronized路上的同学一些帮助。

?

重量级的膨胀和加锁流程

当出现多个线程同时竞争锁时,会进入到synchronizer.cpp#slow_enter方法

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())?{
????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;
??}

?...
?

??//?这时候需要膨胀为重量级锁,膨胀前,设置Displaced?Mark?Word为一个特殊值,代表该锁正在用一个重量级锁的monitor
??lock->set_displaced_header(markOopDesc::unused_mark());
??//先调用inflate膨胀为重量级锁,该方法返回一个ObjectMonitor对象,然后调用其enter方法
??ObjectSynchronizer::inflate(THREAD,?obj())->enter(THREAD);
}

inflate中完成膨胀过程。

ObjectMonitor?*?ATTR?ObjectSynchronizer::inflate?(Thread?*?Self,?oop?object)?{
??...

??for?(;;)?{
??????const?markOop?mark?=?object->mark()?;
??????assert?(!mark->has_bias_pattern(),?"invariant")?;
????
??????//?mark是以下状态中的一种:
??????//?*??Inflated(重量级锁状态)?????-?直接返回
??????//?*??Stack-locked(轻量级锁状态)?-?膨胀
??????//?*??INFLATING(膨胀中)????-?忙等待直到膨胀完成
??????//?*??Neutral(无锁状态)??????-?膨胀
??????//?*??BIASED(偏向锁)???????-?非法状态,在这里不会出现

??????//?CASE:?inflated
??????if?(mark->has_monitor())?{
??????????//?已经是重量级锁状态了,直接返回
??????????ObjectMonitor?*?inf?=?mark->monitor()?;
??????????...
??????????return?inf?;
??????}

??????//?CASE:?inflation?in?progress
??????if?(mark?==?markOopDesc::INFLATING())?{
?????????//?正在膨胀中,说明另一个线程正在进行锁膨胀,continue重试
?????????TEVENT?(Inflate:?spin?while?INFLATING)?;
?????????//?在该方法中会进行spin/yield/park等操作完成自旋动作?
?????????ReadStableMark(object)?;
?????????continue?;
??????}
?
??????if?(mark->has_locker())?{
??????????//?当前轻量级锁状态,先分配一个ObjectMonitor对象,并初始化值
??????????ObjectMonitor?*?m?=?omAlloc?(Self)?;
??????????
??????????m->Recycle();
??????????m->_Responsible??=?NULL?;
??????????m->OwnerIsThread?=?0?;
??????????m->_recursions???=?0?;
??????????m->_SpinDuration?=?ObjectMonitor::Knob_SpinLimit?;???//?Consider:?maintain?by?type/class
		??//?将锁对象的mark?word设置为INFLATING?(0)状态?
??????????markOop?cmp?=?(markOop)?Atomic::cmpxchg_ptr?(markOopDesc::INFLATING(),?object->mark_addr(),?mark)?;
??????????if?(cmp?!=?mark)?{
?????????????omRelease?(Self,?m,?true)?;
?????????????continue?;???????//?Interference?--?just?retry
??????????}

??????????//?栈中的displaced?mark?word
??????????markOop?dmw?=?mark->displaced_mark_helper()?;
??????????assert?(dmw->is_neutral(),?"invariant")?;

??????????//?设置monitor的字段
??????????m->set_header(dmw)?;
??????????//?owner为Lock?Record
??????????m->set_owner(mark->locker());
??????????m->set_object(object);
??????????...
??????????//?将锁对象头设置为重量级锁状态
??????????object->release_set_mark(markOopDesc::encode(m));

?????????...
??????????return?m?;
??????}

??????//?CASE:?neutral
??	?
??????//?分配以及初始化ObjectMonitor对象
??????ObjectMonitor?*?m?=?omAlloc?(Self)?;
??????//?prepare?m?for?installation?-?set?monitor?to?initial?state
??????m->Recycle();
??????m->set_header(mark);
??????//?owner为NULL
??????m->set_owner(NULL);
??????m->set_object(object);
??????m->OwnerIsThread?=?1?;
??????m->_recursions???=?0?;
??????m->_Responsible??=?NULL?;
??????m->_SpinDuration?=?ObjectMonitor::Knob_SpinLimit?;???????//?consider:?keep?metastats?by?type/class
	??//?用CAS替换对象头的mark?word为重量级锁状态
??????if?(Atomic::cmpxchg_ptr?(markOopDesc::encode(m),?object->mark_addr(),?mark)?!=?mark)?{
??????????//?不成功说明有另外一个线程在执行inflate,释放monitor对象
??????????m->set_object?(NULL)?;
??????????m->set_owner??(NULL)?;
??????????m->OwnerIsThread?=?0?;
??????????m->Recycle()?;
??????????omRelease?(Self,?m,?true)?;
??????????m?=?NULL?;
??????????continue?;
??????????//?interference?-?the?markword?changed?-?just?retry.
??????????//?The?state-transitions?are?one-way,?so?there's?no?chance?of
??????????//?live-lock?--?"Inflated"?is?an?absorbing?state.
??????}

??????...
??????return?m?;
??}
}

inflate中是一个for循环,主要是为了处理多线程同时调用inflate的情况。然后会根据锁对象的状态进行不同的处理:

1.已经是重量级状态,说明膨胀已经完成,直接返回

2.如果是轻量级锁则需要进行膨胀操作

3.如果是膨胀中状态,则进行忙等待

4.如果是无锁状态则需要进行膨胀操作

其中轻量级锁和无锁状态需要进行膨胀操作,轻量级锁膨胀流程如下:

1.调用omAlloc分配一个ObjectMonitor对象(以下简称monitor),空中城市娱乐登入:在omAlloc方法中会先从线程私有的monitor集合omFreeList中分配对象,如果omFreeList中已经没有monitor对象,则从JVM全局的gFreeList中分配一批monitoromFreeList中。

2.初始化monitor对象

3.将状态设置为膨胀中(INFLATING)状态

4.设置monitor的header字段为displaced mark word,owner字段为Lock Record,obj字段为锁对象

5.设置锁对象头的mark word为重量级锁状态,指向第一步分配的monitor对象

无锁状态下的膨胀流程如下:

1.调用omAlloc分配一个ObjectMonitor对象(以下简称monitor)

2.初始化monitor对象

3.设置monitor的header字段为?mark word,owner字段为null,obj字段为锁对象

4.设置锁对象头的mark word为重量级锁状态,指向第一步分配的monitor对象

至于为什么轻量级锁需要一个膨胀中(INFLATING)状态,代码中的注释是:

//?Why?do?we?CAS?a?0?into?the?mark-word?instead?of?just?CASing?the
//?mark-word?from?the?stack-locked?value?directly?to?the?new?inflated?state?
//?Consider?what?happens?when?a?thread?unlocks?a?stack-locked?object.
//?It?attempts?to?use?CAS?to?swing?the?displaced?header?value?from?the
//?on-stack?basiclock?back?into?the?object?header.??Recall?also?that?the
//?header?value?(hashcode,?etc)?can?reside?in?(a)?the?object?header,?or
//?(b)?a?displaced?header?associated?with?the?stack-lock,?or?(c)?a?displaced
//?header?in?an?objectMonitor.??The?inflate()?routine?must?copy?the?header
//?value?from?the?basiclock?on?the?owner's?stack?to?the?objectMonitor,?all
//?the?while?preserving?the?hashCode?stability?invariants.??If?the?owner
//?decides?to?release?the?lock?while?the?value?is?0,?the?unlock?will?fail
//?and?control?will?eventually?pass?from?slow_exit()?to?inflate.??The?owner
//?will?then?spin,?waiting?for?the?0?value?to?disappear.???Put?another?way,
//?the?0?causes?the?owner?to?stall?if?the?owner?happens?to?try?to
//?drop?the?lock?(restoring?the?header?from?the?basiclock?to?the?object)
//?while?inflation?is?in-progress.??This?protocol?avoids?races?that?might
//?would?otherwise?permit?hashCode?values?to?change?or?"flicker"?for?an?object.
//?Critically,?while?object->mark?is?0?mark->displaced_mark_helper()?is?stable.
//?0?serves?as?a?"BUSY"?inflate-in-progress?indicator.

我没太看懂,有知道的同学可以指点下~

膨胀完成之后,会调用enter方法获得锁

void?ATTR?ObjectMonitor::enter(TRAPS)?{
???
??Thread?*?const?Self?=?THREAD?;
??void?*?cur?;
??//?owner为null代表无锁状态,如果能CAS设置成功,则当前线程直接获得锁
??cur?=?Atomic::cmpxchg_ptr?(Self,?&_owner,?NULL)?;
??if?(cur?==?NULL)?{
?????...
?????return?;
??}
??//?如果是重入的情况
??if?(cur?==?Self)?{
?????//?TODO-FIXME:?check?for?integer?overflow!??BUGID?6557169.
?????_recursions?++?;
?????return?;
??}
??//?当前线程是之前持有轻量级锁的线程。由轻量级锁膨胀且第一次调用enter方法,那cur是指向Lock?Record的指针
??if?(Self->is_lock_owned?((address)cur))?{
????assert?(_recursions?==?0,?"internal?state?error");
????//?重入计数重置为1
????_recursions?=?1?;
????//?设置owner字段为当前线程(之前owner是指向Lock?Record的指针)
????_owner?=?Self?;
????OwnerIsThread?=?1?;
????return?;
??}

??...

??//?在调用系统的同步操作之前,先尝试自旋获得锁
??if?(Knob_SpinEarly?&&?TrySpin?(Self)?>?0)?{
?????...
?????//自旋的过程中获得了锁,则直接返回
?????Self->_Stalled?=?0?;
?????return?;
??}

??...

??{?
????...

????for?(;;)?{
??????jt->set_suspend_equivalent();
??????//?在该方法中调用系统同步操作
??????EnterI?(THREAD)?;
??????...
????}
????Self->set_current_pending_monitor(NULL);
????
??}

??...

}
  1. 如果当前是无锁状态、锁重入、当前线程是之前持有轻量级锁的线程则进行简单操作后返回。

  2. 先自旋尝试获得锁,这样做的目的是为了减少执行操作系统同步操作带来的开销

  3. 调用EnterI方法获得锁或阻塞

EnterI方法比较长,在看之前,我们先阐述下其大致原理:

一个ObjectMonitor对象包括这么几个关键字段:cxq(下图中的ContentionList),EntryList ,WaitSet,owner。

其中cxq ,EntryList ,WaitSet都是由ObjectWaiter的链表结构,owner指向持有锁的线程。

当一个线程尝试获得锁时,如果该锁已经被占用,则会将该线程封装成一个ObjectWaiter对象插入到cxq的队列的队首,然后调用park函数挂起当前线程。在linux系统上,park函数底层调用的是gclib库的pthread_cond_wait,JDK的ReentrantLock底层也是用该方法挂起线程的。更多细节可以看我之前的两篇文章:关于同步的一点思考-下linux内核级同步机制–futex

当线程释放锁时,会从cxq或EntryList中挑选一个线程唤醒,被选中的线程叫做Heir presumptive即假定继承人(应该是这样翻译),就是图中的Ready Thread,假定继承人被唤醒后会尝试获得锁,但synchronized是非公平的,所以假定继承人不一定能获得锁(这也是它叫”假定”继承人的原因)。

如果线程获得锁后调用Object#wait方法,则会将线程加入到WaitSet中,当被Object#notify唤醒后,会将线程从WaitSet移动到cxq或EntryList中去。需要注意的是,当调用一个锁对象的waitnotify方法时,如当前锁的状态是偏向锁或轻量级锁则会先膨胀成重量级锁

synchronizedmonitor锁机制和JDK的ReentrantLockCondition是很相似的,ReentrantLock也有一个存放等待获取锁线程的链表,Condition也有一个类似WaitSet的集合用来存放调用了await的线程。如果你之前对ReentrantLock有深入了解,那理解起monitor应该是很简单。

回到代码上,开始分析EnterI方法:

void?ATTR?ObjectMonitor::EnterI?(TRAPS)?{
????Thread?*?Self?=?THREAD?;
????...
????//?尝试获得锁
????if?(TryLock?(Self)?>?0)?{
????????...
????????return?;
????}

????DeferredInitialize?()?;
?
	//?自旋
????if?(TrySpin?(Self)?>?0)?{
????????...
????????return?;
????}
????
????...
	
????//?将线程封装成node节点中
????ObjectWaiter?node(Self)?;
????Self->_ParkEvent->reset()?;
????node._prev???=?(ObjectWaiter?*)?0xBAD?;
????node.TState??=?ObjectWaiter::TS_CXQ?;

????//?将node节点插入到_cxq队列的头部,cxq是一个单向链表
????ObjectWaiter?*?nxt?;
????for?(;;)?{
????????node._next?=?nxt?=?_cxq?;
????????if?(Atomic::cmpxchg_ptr?(&node,?&_cxq,?nxt)?==?nxt)?break?;

????????//?CAS失败的话?再尝试获得锁,这样可以降低插入到_cxq队列的频率
????????if?(TryLock?(Self)?>?0)?{
????????????...
????????????return?;
????????}
????}

	//?SyncFlags默认为0,如果没有其他等待的线程,则将_Responsible设置为自己
????if?((SyncFlags?&?16)?==?0?&&?nxt?==?NULL?&&?_EntryList?==?NULL)?{
????????Atomic::cmpxchg_ptr?(Self,?&_Responsible,?NULL)?;
????}


????TEVENT?(Inflated?enter?-?Contention)?;
????int?nWakeups?=?0?;
????int?RecheckInterval?=?1?;

????for?(;;)?{

????????if?(TryLock?(Self)?>?0)?break?;
????????assert?(_owner?!=?Self,?"invariant")?;

????????...

????????//?park?self
????????if?(_Responsible?==?Self?||?(SyncFlags?&?1))?{
????????????//?当前线程是_Responsible时,调用的是带时间参数的park
????????????TEVENT?(Inflated?enter?-?park?TIMED)?;
????????????Self->_ParkEvent->park?((jlong)?RecheckInterval)?;
????????????//?Increase?the?RecheckInterval,?but?clamp?the?value.
????????????RecheckInterval?*=?8?;
????????????if?(RecheckInterval?>?1000)?RecheckInterval?=?1000?;
????????}?else?{
????????????//否则直接调用park挂起当前线程
????????????TEVENT?(Inflated?enter?-?park?UNTIMED)?;
????????????Self->_ParkEvent->park()?;
????????}

????????if?(TryLock(Self)?>?0)?break?;

????????...
????????
????????if?((Knob_SpinAfterFutile?&?1)?&&?TrySpin?(Self)?>?0)?break?;

???????	...
????????//?在释放锁时,_succ会被设置为EntryList或_cxq中的一个线程
????????if?(_succ?==?Self)?_succ?=?NULL?;

????????//?Invariant:?after?clearing?_succ?a?thread?*must*?retry?_owner?before?parking.
????????OrderAccess::fence()?;
????}

???//?走到这里说明已经获得锁了

????assert?(_owner?==?Self??????,?"invariant")?;
????assert?(object()?!=?NULL????,?"invariant")?;
??
	//?将当前线程的node从cxq或EntryList中移除
????UnlinkAfterAcquire?(Self,?&node)?;
????if?(_succ?==?Self)?_succ?=?NULL?;
	if?(_Responsible?==?Self)?{
????????_Responsible?=?NULL?;
????????OrderAccess::fence();
????}
????...
????return?;
}

主要步骤有3步:

  1. 将当前线程插入到cxq队列的队首

  2. 然后park当前线程

  3. 当被唤醒后再尝试获得锁

这里需要特别说明的是_Responsible_succ两个字段的作用:

当竞争发生时,选取一个线程作为_Responsible_Responsible线程调用的是有时间限制的park方法,其目的是防止出现搁浅现象。

_succ线程是在线程释放锁是被设置,其含义是Heir presumptive,也就是我们上面说的假定继承人。

重量级锁的释放

重量级锁释放的代码在ObjectMonitor::exit

void?ATTR?ObjectMonitor::exit(bool?not_suspended,?TRAPS)?{
???Thread?*?Self?=?THREAD?;
???//?如果_owner不是当前线程
???if?(THREAD?!=?_owner)?{
?????//?当前线程是之前持有轻量级锁的线程。由轻量级锁膨胀后还没调用过enter方法,_owner会是指向Lock?Record的指针。
?????if?(THREAD->is_lock_owned((address)?_owner))?{
???????assert?(_recursions?==?0,?"invariant")?;
???????_owner?=?THREAD?;
???????_recursions?=?0?;
???????OwnerIsThread?=?1?;
?????}?else?{
???????//?异常情况:当前不是持有锁的线程
???????TEVENT?(Exit?-?Throw?IMSX)?;
???????assert(false,?"Non-balanced?monitor?enter/exit!");
???????if?(false)?{
??????????THROW(vmSymbols::java_lang_IllegalMonitorStateException());
???????}
???????return;
?????}
???}
???//?重入计数器还不为0,则计数器-1后返回
???if?(_recursions?!=?0)?{
?????_recursions--;????????//?this?is?simple?recursive?enter
?????TEVENT?(Inflated?exit?-?recursive)?;
?????return?;
???}

???//?_Responsible设置为null
???if?((SyncFlags?&?4)?==?0)?{
??????_Responsible?=?NULL?;
???}

???...

???for?(;;)?{
??????assert?(THREAD?==?_owner,?"invariant")?;

??????//?Knob_ExitPolicy默认为0
??????if?(Knob_ExitPolicy?==?0)?{
?????????//?code?1:先释放锁,这时如果有其他线程进入同步块则能获得锁
?????????OrderAccess::release_store_ptr?(&_owner,?NULL)?;???//?drop?the?lock
?????????OrderAccess::storeload()?;?????????????????????????//?See?if?we?need?to?wake?a?successor
?????????//?code?2:如果没有等待的线程或已经有假定继承人
?????????if?((intptr_t(_EntryList)|intptr_t(_cxq))?==?0?||?_succ?!=?NULL)?{
????????????TEVENT?(Inflated?exit?-?simple?egress)?;
????????????return?;
?????????}
?????????TEVENT?(Inflated?exit?-?complex?egress)?;

?????????//?code?3:要执行之后的操作需要重新获得锁,即设置_owner为当前线程
?????????if?(Atomic::cmpxchg_ptr?(THREAD,?&_owner,?NULL)?!=?NULL)?{
????????????return?;
?????????}
?????????TEVENT?(Exit?-?Reacquired)?;
??????}?
??????...

??????ObjectWaiter?*?w?=?NULL?;
??????//?code?4:根据QMode的不同会有不同的唤醒策略,默认为0
??????int?QMode?=?Knob_QMode?;
	?
??????if?(QMode?==?2?&&?_cxq?!=?NULL)?{
??????????//?QMode?==?2?:?cxq中的线程有更高优先级,直接唤醒cxq的队首线程
??????????w?=?_cxq?;
??????????assert?(w?!=?NULL,?"invariant")?;
??????????assert?(w->TState?==?ObjectWaiter::TS_CXQ,?"Invariant")?;
??????????ExitEpilog?(Self,?w)?;
??????????return?;
??????}

??????if?(QMode?==?3?&&?_cxq?!=?NULL)?{
??????????//?将cxq中的元素插入到EntryList的末尾
??????????w?=?_cxq?;
??????????for?(;;)?{
?????????????assert?(w?!=?NULL,?"Invariant")?;
?????????????ObjectWaiter?*?u?=?(ObjectWaiter?*)?Atomic::cmpxchg_ptr?(NULL,?&_cxq,?w)?;
?????????????if?(u?==?w)?break?;
?????????????w?=?u?;
??????????}
??????????assert?(w?!=?NULL??????????????,?"invariant")?;

??????????ObjectWaiter?*?q?=?NULL?;
??????????ObjectWaiter?*?p?;
??????????for?(p?=?w?;?p?!=?NULL?;?p?=?p->_next)?{
??????????????guarantee?(p->TState?==?ObjectWaiter::TS_CXQ,?"Invariant")?;
??????????????p->TState?=?ObjectWaiter::TS_ENTER?;
??????????????p->_prev?=?q?;
??????????????q?=?p?;
??????????}

??????????//?Append?the?RATs?to?the?EntryList
??????????//?TODO:?organize?EntryList?as?a?CDLL?so?we?can?locate?the?tail?in?constant-time.
??????????ObjectWaiter?*?Tail?;
??????????for?(Tail?=?_EntryList?;?Tail?!=?NULL?&&?Tail->_next?!=?NULL?;?Tail?=?Tail->_next)?;
??????????if?(Tail?==?NULL)?{
??????????????_EntryList?=?w?;
??????????}?else?{
??????????????Tail->_next?=?w?;
??????????????w->_prev?=?Tail?;
??????????}

??????????//?Fall?thru?into?code?that?tries?to?wake?a?successor?from?EntryList
??????}

??????if?(QMode?==?4?&&?_cxq?!=?NULL)?{
??????????//?将cxq插入到EntryList的队首
??????????w?=?_cxq?;
??????????for?(;;)?{
?????????????assert?(w?!=?NULL,?"Invariant")?;
?????????????ObjectWaiter?*?u?=?(ObjectWaiter?*)?Atomic::cmpxchg_ptr?(NULL,?&_cxq,?w)?;
?????????????if?(u?==?w)?break?;
?????????????w?=?u?;
??????????}
??????????assert?(w?!=?NULL??????????????,?"invariant")?;

??????????ObjectWaiter?*?q?=?NULL?;
??????????ObjectWaiter?*?p?;
??????????for?(p?=?w?;?p?!=?NULL?;?p?=?p->_next)?{
??????????????guarantee?(p->TState?==?ObjectWaiter::TS_CXQ,?"Invariant")?;
??????????????p->TState?=?ObjectWaiter::TS_ENTER?;
??????????????p->_prev?=?q?;
??????????????q?=?p?;
??????????}

??????????//?Prepend?the?RATs?to?the?EntryList
??????????if?(_EntryList?!=?NULL)?{
??????????????q->_next?=?_EntryList?;
??????????????_EntryList->_prev?=?q?;
??????????}
??????????_EntryList?=?w?;

??????????//?Fall?thru?into?code?that?tries?to?wake?a?successor?from?EntryList
??????}

??????w?=?_EntryList??;
??????if?(w?!=?NULL)?{
??????????//?如果EntryList不为空,则直接唤醒EntryList的队首元素
??????????assert?(w->TState?==?ObjectWaiter::TS_ENTER,?"invariant")?;
??????????ExitEpilog?(Self,?w)?;
??????????return?;
??????}

??????//?EntryList为null,则处理cxq中的元素
??????w?=?_cxq?;
??????if?(w?==?NULL)?continue?;

??????//?因为之后要将cxq的元素移动到EntryList,所以这里将cxq字段设置为null
??????for?(;;)?{
??????????assert?(w?!=?NULL,?"Invariant")?;
??????????ObjectWaiter?*?u?=?(ObjectWaiter?*)?Atomic::cmpxchg_ptr?(NULL,?&_cxq,?w)?;
??????????if?(u?==?w)?break?;
??????????w?=?u?;
??????}
??????TEVENT?(Inflated?exit?-?drain?cxq?into?EntryList)?;

??????assert?(w?!=?NULL??????????????,?"invariant")?;
??????assert?(_EntryList??==?NULL????,?"invariant")?;


??????if?(QMode?==?1)?{
?????????//?QMode?==?1?:?将cxq中的元素转移到EntryList,并反转顺序
?????????ObjectWaiter?*?s?=?NULL?;
?????????ObjectWaiter?*?t?=?w?;
?????????ObjectWaiter?*?u?=?NULL?;
?????????while?(t?!=?NULL)?{
?????????????guarantee?(t->TState?==?ObjectWaiter::TS_CXQ,?"invariant")?;
?????????????t->TState?=?ObjectWaiter::TS_ENTER?;
?????????????u?=?t->_next?;
?????????????t->_prev?=?u?;
?????????????t->_next?=?s?;
?????????????s?=?t;
?????????????t?=?u?;
?????????}
?????????_EntryList??=?s?;
?????????assert?(s?!=?NULL,?"invariant")?;
??????}?else?{
?????????//?QMode?==?0?or?QMode?==?2‘
?????????//?将cxq中的元素转移到EntryList
?????????_EntryList?=?w?;
?????????ObjectWaiter?*?q?=?NULL?;
?????????ObjectWaiter?*?p?;
?????????for?(p?=?w?;?p?!=?NULL?;?p?=?p->_next)?{
?????????????guarantee?(p->TState?==?ObjectWaiter::TS_CXQ,?"Invariant")?;
?????????????p->TState?=?ObjectWaiter::TS_ENTER?;
?????????????p->_prev?=?q?;
?????????????q?=?p?;
?????????}
??????}


??????//?_succ不为null,说明已经有个继承人了,所以不需要当前线程去唤醒,减少上下文切换的比率
??????if?(_succ?!=?NULL)?continue;

??????w?=?_EntryList??;
??????//?唤醒EntryList第一个元素
??????if?(w?!=?NULL)?{
??????????guarantee?(w->TState?==?ObjectWaiter::TS_ENTER,?"invariant")?;
??????????ExitEpilog?(Self,?w)?;
??????????return?;
??????}
???}
}

在进行必要的锁重入判断以及自旋优化后,进入到主要逻辑:

code 1?设置owner为null,即释放锁,这个时刻其他的线程能获取到锁。这里是一个非公平锁的优化;

code 2?如果当前没有等待的线程则直接返回就好了,因为不需要唤醒其他线程。或者如果说succ不为null,代表当前已经有个”醒着的”继承人线程,那当前线程不需要唤醒任何线程;

code 3?当前线程重新获得锁,因为之后要操作cxq和EntryList队列以及唤醒线程;

code 4根据QMode的不同,会执行不同的唤醒策略;

根据QMode的不同,有不同的处理方式:

  1. QMode = 2且cxq非空:取cxq队列队首的ObjectWaiter对象,调用ExitEpilog方法,该方法会唤醒ObjectWaiter对象的线程,然后立即返回,后面的代码不会执行了;

  2. QMode = 3且cxq非空:把cxq队列插入到EntryList的尾部;

  3. QMode = 4且cxq非空:把cxq队列插入到EntryList的头部;

  4. QMode = 0:暂时什么都不做,继续往下看;

只有QMode=2的时候会提前返回,等于0、3、4的时候都会继续往下执行:

1.如果EntryList的首元素非空,就取出来调用ExitEpilog方法,该方法会唤醒ObjectWaiter对象的线程,然后立即返回;
2.如果EntryList的首元素为空,就将cxq的所有元素放入到EntryList中,然后再从EntryList中取出来队首元素执行ExitEpilog方法,然后立即返回;

QMode默认为0,结合上面的流程我们可以看这么个demo:

public?class?SyncDemo?{

????public?static?void?main(String[]?args)?{

????????SyncDemo?syncDemo1?=?new?SyncDemo();
????????syncDemo1.startThreadA();
????????try?{
????????????Thread.sleep(100);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????syncDemo1.startThreadB();
????????try?{
????????????Thread.sleep(100);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????syncDemo1.startThreadC();
???????

????}

????final?Object?lock?=?new?Object();


????public?void?startThreadA()?{
????????new?Thread(()?->?{
????????????synchronized?(lock)?{
????????????????System.out.println("A?get?lock");
????????????????try?{
????????????????????Thread.sleep(500);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("A?release?lock");
????????????}
????????},?"thread-A").start();
????}

????public?void?startThreadB()?{
????????new?Thread(()?->?{
????????????synchronized?(lock)?{
????????????????System.out.println("B?get?lock");
????????????}
????????},?"thread-B").start();
????}

????public?void?startThreadC()?{
????????new?Thread(()?->?{
????????????synchronized?(lock)?{

????????????????System.out.println("C?get?lock");
????????????}
????????},?"thread-C").start();
????}


}

默认策略下,在A释放锁后一定是C线程先获得锁。因为在获取锁时,是将当前线程插入到cxq的头部,而释放锁时,默认策略是:如果EntryList为空,则将cxq中的元素按原有顺序插入到到EntryList,并唤醒第一个线程。也就是当EntryList为空时,是后来的线程先获取锁。这点JDK中的Lock机制是不一样的。

?

Synchronized和ReentrantLock的区别

原理弄清楚了,顺便总结了几点Synchronized和ReentrantLock的区别:

  1. Synchronized是JVM层次的锁实现,ReentrantLock是JDK层次的锁实现;

  2. Synchronized的锁状态是无法在代码中直接判断的,但是ReentrantLock可以通过ReentrantLock#isLocked判断;

  3. Synchronized是非公平锁,ReentrantLock是可以是公平也可以是非公平的;

  4. Synchronized是不可以被中断的,而ReentrantLock#lockInterruptibly方法是可以被中断的;

  5. 在发生异常时Synchronized会自动释放锁(由javac编译时自动实现),而ReentrantLock需要开发者在finally块中显示释放锁;

  6. ReentrantLock获取锁的形式有多种:如立即返回是否成功的tryLock(),以及等待指定时长的获取,更加灵活;

  7. Synchronized在特定的情况下对于已经在等待的线程是后来的线程先获得锁(上文有说),而ReentrantLock对于已经在等待的线程一定是先来的线程先获得锁;

?

End

总的来说Synchronized的重量级锁和ReentrantLock的实现上还是有很多相似的,包括其数据结构、挂起线程方式等等。在日常使用中,如无特殊要求用Synchronized就够了。你深入了解这两者其中一个的实现,了解另外一个或其他锁机制都比较容易,这也是我们常说的技术上的相通性。