,可以理解为可重入锁。来看看它的底层实现吧~我们在使用构造函数的时候,总是先new它,所以先来看看吧。构造函数,它主要有两个:publicReentrantLock(){sync=newNonfairSync();}publicReentrantLock(booleanfair){sync=fair?newFairSync():newNonfairSync();}从字面上看,它们之间的区别是fair,翻译过来就是公平的意思。大致可以猜到是用来构建公平锁和非公平锁的。在继续往下看源码之前,先科普一下这两款锁。公平锁&非公平锁公平锁多个线程按照申请锁的顺序获取锁。线程会直接进入队列排队,永远是队列中最先获得锁的。(比如银行业务取号)这种锁的优点很明显,每个线程都可以获得资源,缺点也很明显,如果一个线程被阻塞,其他线程也会被阻塞,但是cpu唤醒成本很高,之前也跟大家讲过非公平锁。多个线程尝试获取锁。如果他们拿不到,他们将进入等待队列。CPU不需要唤醒。优缺点正好与上面相反。拿不到锁或者长时间拿不到锁。有了基本概念之后,我们继续看NonfairSync。首先,让我们看一下非公平锁。默认我们申请的是非公平锁,也就是newReentrantLock(),我们看源码staticfinalclassNonfairSyncextendsSync{privatestaticfinallongserialVersionUID=7316153563782823691L;/***执行锁定。尝试立即插入,备份到正常*失败时获取。*/finalvoidlock(){if(compareAndSetState(0,1))setExclusiveOwnerThread(Thread.currentThread());否则获取(1);}protectedfinalbooleantryAcquire(intacquires){returnnonfairTryAcquire(acquires);}}它继承了Sync,Sync是一个Content静态抽象类:abstractstaticclassSyncextendsAbstractQueuedSynchronizer{...}分为公平和不公平,用AQS状态来表示持有锁的次数,有sync=...当构造函数初始化时,让我们看看NonfairSync。在使用的时候,我们调用lock.lock()方法,它是ReentrantLock的实例方法//获取锁publicvoidlock(){sync.lock();}其实还是调用了sync的内部方法,因为我们申请的是非公平锁,所以我们看一下NonfairSync下的锁实现:finalvoidlock(){if(compareAndSetState(0,1))setExclusiveOwnerThread(Thread.当前线程());elseacquire(1);}compareAndSetState这个方法是AQS的内部方法,意思是如果当前状态值等于期望值,自动设置同步状态为给定的更新值。此操作具有易失性读写的内存语义。protectedfinalbooleancompareAndSetState(intexpect,intupdate){//请参阅下面的内在设置以支持此returnunsafe.compareAndSwapInt(this,stateOffset,expect,update);}可以看到lock方法的执行将计数通过AQS机制,setExclusiveOwnerThread设置线程独占访问权限,它是AbstractOwnableSynchronizer的内部方法,子类用它来管理线程独占publicabstractclassAbstractQueuedSynchronizerextendsAbstractOwnableSynchronizerimplementsjava.io.Serializable{}可以看到它继承了AbstractOwnableSynchronizer。下面看一下,我们说如果实际值等于期望值,就执行上面的方法,如果不等于期望值,就执行。acquire(1)publicfinalvoidacquire(intarg){if(!tryAcquire(arg)&&acquireQueued(addWaiter(Node.EXCLUSIVE),arg))selfInterrupt();}该方法以独占方式获取,忽略中断,它会尝试调用tryAcquire,成功则返回,不成功则进入线程队列,可以反复阻塞和解除阻塞。看看AQS里面的这个方法protectedbooleantryAcquire(intarg){thrownewUnsupportedOperationException();}可以看到实现肯定不是这里,它的具体实现在NonfairSyncprotectedfinalbooleantryAcquire(intacquires){returnnonfairTryAcquire(获得);您可以看到它调用了nonfairTryAcquire方法。这个方法是一个不公平的tryLock。具体实现在Sync里面。这里我们应该关注finalbooleannonfairTryAcquire(intacquires){finalThreadcurrent=Thread.currentThread();//返回同步状态值,这是AQS内部的一个方法//privatevolatileintstate;//protectedfinalintgetState(){//返回状态;//}intc=getState();if(c==0){//如果是0,比较。如果与期望值相同,则设置为独占线程,说明已经获取到锁if(compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);返回真;}}//否则,判断当前线程是否已经设置为独占线程elseif(current==getExclusiveOwnerThread()){//设置当前线程状态值+1,返回成功intnextc=c+acquires;if(nextc<0)//溢出抛出newError(&返回节点;}}enq(节点);返回节点;}我们可以大致猜想Node是一个等待队列和链表结构的节点类。之前我们讲FutureTask的源码的时候也遇到过这种结构。它通常用于自旋锁,在这个地方,它用于阻塞同步器+-----+prev+-----++-----+head||<----||<----||tail+-----++-----++-----+好吧,让我们关注acquireQueuedfinalbooleanacquireQueued(finalNodenode,intarg){booleanfailed=true;try{//默认为falsebooleaninterrupted=false;//进入阻塞循环遍历线程队列for(;;){//返回上一个节点finalNodep=node.predecessor();//判断如果前一个节点是头节点,并且获得了锁,则将当前节点设置为头节点if(p==head&&tryAcquire(arg)){setHead(node);//这里可以看到注释helpgc,p.next=null;//帮助GCfailed=false;返回中断;}//检查并更新失败节点的状态如果线程应该阻塞并且线程被中断则返回trueif(shouldParkAfterFailedAcquire(p,node)&&parkAndCheckInterrupt())interrupted=true;}}finally{//如果失败取消你试图获取的节点if(failed)cancelAcquire(node);}}从上面的源码中,经历了上面说的非公平锁的概念,是不是比较好理解,然后释放锁unlock,可以看出这个方法是ReentrantLock下的一个实例方法,所以释放锁的公平锁也是调整的方法。其实大家可以猜到sync的方法叫publicvoidunlock(){sync.release(1);}Sync继承AQS,release是AQS的内部方法publicfinalbooleanrelease(intarg){//尝试释放Sync内部的锁tryReleaseif(tryRelease(arg)){//如果节点存在且状态值不为0if(h!=null&&h.waitStatus!=0)//唤醒下一个节点unparkSuccessor(h);返回真;}返回假;}privatevoidunparkSuccessor(Nodenode){intws=node.waitStatus;如果(ws<0)compareAndSetWaitStatus(节点,ws,0);节点s=node.next;如果(s==null||s.waitStatus>0){s=null;for(Nodet=tail;t!=null&&t!=node;t=t.prev)if(t.waitStatus<=0)s=t;}if(s!=null)//可以看到调用了LockSupport唤醒LockSupport.unpark(s.thread);}让我们再看看tryRelease,相同的实现在Sync中的protectedfinalboolean中tryRelease(intreleases){//释放锁时也使用AQS计数//判断当前线程是否为独占线程,不抛异常if(Thread.currentThread()!=getExclusiveOwnerThread())thrownewIllegalMonitorStateException();布尔自由=假;//如果为0,表示释放成功if(c==0){free=true;//并将独占线程设置为空setExclusiveOwnerThread(null);}//更新状态值setState(c);免费退货;}FairSync公平锁FairS("超过最大锁数");设置状态(下一步);返回真;}返回假;它的实现比较简单,通过实现可以发现,它是按照申请锁的先后顺序获取锁的,第一个先拿到锁的,结合上面的就很容易理解了概念。释放锁unlock,我们上面已经讲过了~结语这部分内容可能比较多,主要是看源码。可以打断点自己调整,通过源码了解什么是公平锁和非公平锁,ReentrantLock可重入锁体验在哪里
