基于AQS驱动的ReentrantLock公平锁和非公平锁实现原理解析

基于AQS驱动的ReentrantLock公平锁和非公平锁实现原理解析 本文是入门和理解AQS框架的重要文章,尽管AQS还有共享模式以及条件Condition等设计,但重入锁仍然是最适合理解AQS底层数据结构及其算法设计的切入点。单线程使用可重入锁的内部简单工作机制分别在以下两个断点位置进行debug,断点条件i==5,并且在variables窗口watch一个特殊的变量stateimportjava.util.concurrent.locks.ReentrantLock;publicclassReentrantLockDemo{publicstaticReentrantLocklock=newReentrantLock();publicstaticvoidmain(String[]args){for(inti=1;i=5;i++){lock.lock();// 断点位置}for(inti=1;i=5;i++){lock.unlock();// 断点位置}}}可以看到lock.lock()的内部执行流程如下所示,// 1、java.util.concurrent.locks.ReentrantLock$NonfairSync@29444d75[State = 4, empty queue]publicvoidlock(){sync.lock();}// 2、java.util.concurrent.locks.ReentrantLockfinalvoidlock(){if(compareAndSetState(0,1))// 重点:使用cas更新state的值setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}// 3、java.util.concurrent.locks.AbstractQueuedSynchronizerprotectedfinalbooleancompareAndSetState(intexpect,intupdate){// See below for intrinsics setup to support thisreturnunsafe.compareAndSwapInt(this,stateOffset,expect,update);}// 4、java.util.concurrent.locks.AbstractQueuedSynchronizerpublicfinalvoidacquire(intarg){if(!tryAcquire(arg)// 调用下面5在ReentrantLock定义的tryAcquire方法acquireQueued(addWaiter(Node.EXCLUSIVE),arg))selfInterrupt();}// 5、java.util.concurrent.locks.ReentrantLockprotectedfinalbooleantryAcquire(intacquires){returnnonfairTryAcquire(acquires);}// 6、java.util.concurrent.locks.ReentrantLockfinalbooleannonfairTryAcquire(intacquires){finalThreadcurrent=Thread.currentThread();intc=getState();// 重点:获取state变量当前值if(c==0){if(compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);returntrue;}}elseif(current==getExclusiveOwnerThread()){intnextc=c+acquires;if(nextc0)// overflowthrownewError("Maximum lock count exceeded");setState(nextc);// 重点:更新state变量值returntrue;}returnfalse;}经过这么一轮debug,可以观察到原来lock.lock()通过cas更改state变量值来实现“可重入性”,例如,这里for循环5次使得该线程在同一锁对象上加锁了5次,可以看到对应的state累加计数等于5,基于此可以推出lock.unlock()操作则是每次unlock()就是对state进行cas减1操作,如下://1、java.util.concurrent.locks.ReentrantLockpublicvoidunlock(){sync.release(1);}// 2、java.util.concurrent.locks.AbstractQueuedSynchronizerpublicfinalbooleanrelease(intarg){if(tryRelease(arg)){Nodeh=head;if(h!=nullh.waitStatus!=0)unparkSuccessor(h);returntrue;}returnfalse;}//3、java.util.concurrent.locks.ReentrantLockprotectedfinalbooleantryRelease(intreleases){intc=getState()-releases;// 当i=5次循环时,这里getState=1,releases=1if(Thread.currentThread()!=getExclusiveOwnerThread())thrownewIllegalMonitorStateException();booleanfree=false;if(c==0){// 所有的重入都退出后,此刻不再有线程持有独占锁。free=true;setExclusiveOwnerThread(null);}setState(c);// 当i=5次循环时,state被置为0returnfree;}其实这个state变量是一个非常重要的“同步状态”,记录了当前持有独占锁的线程的重入加锁次数,它在AbstractQueuedSynchronizer内部定义:/** * The synchronization state. */privatevolatileintstate;从ReentrantLock以上两个流程来看,重点需要解析sync.lock()、sync.release(1),而这里sync实例是来自ReentrantLock内部定义Sync类,该类继承至AbstractQueuedSynchronizer,因此如果要真正理解ReentrantLock的可重入性,则需要深入底层的`AbstractQueuedSynchronizer,这是JUC众多锁工具的底层实现。从Sync类了解AQS在真正解析AQS之前,可以先看看在ReentrantLock内部定义的Sync,以下按ReentrantLock默认构造器进入分析流程publicReentrantLock(){sync=newNonfairSync();}NonfairSync是实现非公平锁的主要逻辑/** * Sync object for non-fair locks */staticfinalclassNonfairSyncextendsSync{privatestaticfinallongserialVersionUID=7316153563782823691L;/** # 这里说,当前线程当前直接无需排队去争抢锁资源,也即不是先到先到,所以是才称为非公平模式。抢不到才去阻塞队列里面排队 * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */finalvoidlock(){if(compareAndSetState(0,1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protectedfinalbooleantryAcquire(intacquires){returnnonfairTryAcquire(acquires);}}Sync类定义了获取锁的分配逻辑,这里涉及到对同步状态state更改、同一线程的锁重入、锁重入释放/** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */abstractstaticclassSyncextendsAbstractQueuedSynchronizer{privatestaticfinallongserialVersionUID=-5179523762034025860L;/** * Performs {@link Lock#lock}. The main reason for subclassing * is to allow fast path for nonfair version. */abstractvoidlock();/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */finalbooleannonfairTryAcquire(intacquires){finalThreadcurrent=Thread.currentThread();intc=getState();if(c==0){if(compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);returntrue;}}elseif(current==getExclusiveOwnerThread()){intnextc=c+acquires;if(nextc0)// overflowthrownewError("Maximum lock count exceeded");setState(nextc);returntrue;}returnfalse;}protectedfinalbooleantryRelease(intreleases){intc=getState()-releases;if(Thread.currentThread()!=getExclusiveOwnerThread())thrownewIllegalMonitorStateException();booleanfree=false;if(c==0){free=true;setExclusiveOwnerThread(null);}setState(c);returnfree;}protectedfinalbooleanisHeldExclusively(){// While we must in general read state before owner,// we don't need to do so to check if current thread is ownerreturngetExclusiveOwnerThread()==Thread.currentThread();}finalConditionObjectnewCondition(){returnnewConditionObject();}// Methods relayed from outer classfinalThreadgetOwner(){returngetState()==0?null:getExclusiveOwnerThread();}finalintgetHoldCount(){returnisHeldExclusively()?getState():0;}finalbooleanisLocked(){returngetState()!=0;}/** * Reconstitutes the instance from a stream (that is, deserializes it). */privatevoidreadObject(java.io.ObjectInputStreams)throwsjava.io.IOException