大家对于ReentrantLock应该都不陌生吧,那么你对于它的实现原理又了解多少呢?下面就和小编一起来了解一下ReentrantLock的实现原理吧!
一、实现原理
ReentrantLock主要是通过CAS+CLH队列来实现。
它支持公平锁和非公平锁,两者的实现都是非常的类似。
ReentrantLock的基本实现:
首先通过CAS尝试获取锁
假如,这个时候已经有线程占据锁了的话,那么就加入CLH队列并且被挂起。
在锁被释放了之后,排在CLH队列队首的线程会被唤醒,之后,CAS再次尝试获取锁。
在这个时候,假如:
1、非公平锁
假如同时还有另外一个线程进来尝试获取,那么的话,就很有可能会让这个线程抢先获取。
2、公平锁
假如,同时还有另外一个线程进来尝试获取,那么,在它发现了自己不是在队列队首的话,就会排到队列队尾,由队首的线程获取到锁。
下面分别对这两个片段进行一下分析:
尝试获取锁时,会先调用下面的的方法。
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
假如,状态是0,那么就表示,这个时候没有人占有锁。
这个时候,尝试进行set,假如成功的话,那么就成功的占有了锁。
假如,状态不是0,就判断是不是当前的线程获取到了锁,假如是的话,那么就将状态+1,这样做的原因是因为,这个时候,就是当前线程,所以就不用CAS。
这个也是可重入锁的实现原理。
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } } private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
这个方法是在尝试获取锁失败加入CHL队尾之后,假如,发现了前序节点是head,那么,CAS再尝试获取一次,否则的话,就会根据前序节点的状态判断是不是需要阻塞,假如,是需要阻塞的话,那么就要调用LockSupport的park方法阻塞这个线程。
以上就是关于ReentrantLock的实现原理的简单介绍了,你都明白了吧!
请继续关注常见问题栏目,更多的java知识问答可以分享给大家。
推荐阅读: