当前位置: 首页 > 科技观察

干货ReentrantLock非公平锁源码分析

时间:2023-03-16 01:10:02 科技观察

本文转载自微信公众号《Java极客技术》,作者鸭血粉。转载本文请联系Java极客技术公众号。1.java中的加锁,加锁的方法是synchronized,是java底层实现的,也就是C语言实现的。.lock,这个在java.util.concurrent包下,用java语言实现。2、ReentrantLockReentrantLock是Lock的一种实现,是一种可重入的公平锁或非公平锁。默认是非公平锁。2.1Lock的创建先看锁的创建和使用代码://创建锁Locklock=newReentrantLock();//加锁lock.lock();//释放锁lock.unlock();然后看创建了ReentrantLock的构造函数:publicReentrantLock(){sync=newNonfairSync();}NonfairSync是非公平锁。所以ReentrantLock默认是非公平锁的实现。2.2由于线程竞争,lock()加锁的逻辑比较复杂。所以有两种情况,一种是竞争锁的处理,一种是不竞争锁的处理。首先我们看lock()方法,因为到底是非公平实现,所以直接看NonfairSync中的lock方法。finalvoidlock(){if(compareAndSetState(0,1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}2.3没有获取锁的逻辑acquire()直接编码:publicfinalvoidacquire(intarg){if(!tryAcquire(arg)&&acquireQueued(addWaiter(Node.EXCLUSIVE),arg))selfInterrupt();}还有3个方法,阿芬一一说了。tryAcquire(arg),还是看分析中的代码。finalbooleannonfairTryAcquire(intacquires){finalThreadcurrent=Thread.currentThread();intc=getState();if(c==0){if(compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);returntrue;}}elseif(当前==getExclusiveOwnerThread()){intnextc=c+acquires;if(nextc<0)//overflowthrownewError("Maximumlockcountexceeded");setState(nextc);returntrue;}returnfalse;}a.获取状态,如果等于0,说明你之前拿到锁的线程已经释放了,那么这个线程会重新去竞争锁。这就是非公平锁的体现。如果是公平锁,就没有这个判断。b.如果上一个获取锁的线程没有释放锁,则判断是否是同一个线程,如果是则状态加1。这就是可重入锁的体现。C。如果两者都不满足,则返回false。acquireQueued(addWaiter(Node.EXCLUSIVE),arg)),如果没有再次成功获取锁,并且锁是不可重入的,那么它会被存储在一个阻塞队列中。里面还有一点逻辑,就不展开了。如果你有兴趣,你可以自己阅读。自中断();这是当前线程的中断标志。它的作用是线程是否被阻塞。如果客户端调用方法interrupt()来中断线程,那么当线程被唤醒时,就会有响应。具体要看threadrun方法中的代码逻辑。2.4unlock()protectedfinalbooleantryRelease(intreleases){intc=getState()-releases;if(Thread.currentThread()!=getExclusiveOwnerThread())thrownewIllegalMonitorStateException();booleanfree=false;if(c==0){free=真的;setExclusiveOwnerThread(null);}setState(c);returnfree;}state-1,如果大于0,表示释放可重入锁,只需要修改state如果等于0,表示需要释放锁。独占线程设置为null,然后state设置为0。3总结Lock锁的实现:互斥:需要一个state来判断是否竞争锁:state和需要用volatile修饰保证线程间的可见性。Reentrancy:ThreadexclusiveOwnerThread这个成员变量记录了当前获取锁的线程。Fairorunfair:默认不公平,NonfairSync。不竞争锁的线程呢?将它们放入队列中。不竞争锁的线程如何释放CPU?park:被阻塞的线程释放CPU资源。这个操作在acquireQueued()中。阿芬没提这个。最后一张流程图: