ReentrantLock 有两种实现锁的方式 一种是非公平的,一种是公平的,默认的实现方式是非公平的,但不管哪种实现方式,ReentrantLock都是依靠的它的静态内部了syc来实现,底层的实现机制都是利用volatitle语义 和操作系统提供的CAS原语来实现
所以在看本篇博文时请确保你有以上基础 ,下面上源码 (jdk1.8)
public ReentrantLock() {
sync = new NonfairSync(); //默认的实现是非公平锁
}
静态内部类的实现
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() { //这里获取锁
if (compareAndSetState(0, 1)) //这里是获取锁的关键
setExclusiveOwnerThread(Thread.currentThread()); //将当前拥有锁的线程置为当前线程,方便重入
else
//获取失败则加入等待队列
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//获取锁的方法
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update); //调用CAS设置锁的状态,如state为0置为1返会true ,否则返回false 获取锁失败
}
还记得前面在lock时 如果失败则会加入队列 ,那当前线程是怎样加入队列的呢? 其实 每个线程都会被封装成一个node节点,每个node节点都有一个前指针prev和后指针next 然后将一个一个node节点连接起来,
接下来我们分析竞争锁失败的情况 失败将会调用
acquire(1);函数
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
我们先看 tryAcquire(arg)
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread(); //获取当前线程
int c = getState(); //获取当前状态 0为可用,1为被锁住
if (c == 0) {
if (!hasQueuedPredecessors() && //hasQueuedPredecessors方法,当节点有前继会放回true,而只有头节点没有
compareAndSetState(0, acquires)) { //重新上锁,只有头节点才能上锁,这里涉及到了公平锁与非公平锁,看后面分析
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //等于当前线程
int nextc = c + acquires; //重入锁
if (nextc < 0)
throw new Error("Maximum lock count exceeded"); //正常不会出现这种情况
setState(nextc); //计数加一
return true;
}
return false;
}
//该方法可以保证能从,头节点开始唤醒
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
//解释一下什么时候会返回真,当h!=t意味着,有节点在等待,(s=h.next)==null,意味着下一个
//节点为空,意味着当前节点可以运行,如果不为空,则比较当前线程是否是节点s中的线程
//如果不是,返回真,意味着当前线程,不是头节点的next的中的线程,则放回true;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
tryAcquire 有两个作用,第一个作用是 再一次竞争锁,虽然线程在第一次竞争失败但有可能持有锁的线程持有时间非常短,
所以重新竞争
第二个作用是方便锁的冲入,一个线程可以重入该锁 并将计数加一,否则返回false
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
上面的判断是个&&判断,当第一个为!tryAcquire(arg) 为假时直接返回,说明当前竞争的线程是冲入或者持有锁的线程释放后被线程获取,假设,线程没有获取到 则会执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg))首先让我们先看下addWaiter(Node.EXCLUSIVE)方法 其中Node.EXCLUSIVE是个常量值 为空
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);//创建一个节点,并将当前线程赋予该节点
// Try the fast path of enq; backup to full enq on failure
Node pred = tail; //取出尾节点
if (pred != null) { //接下来的操作是将当前节点加入到链表的为节点
node.prev = pred;
if (compareAndSetTail(pred, node)) { //可能这里你会有疑问如果失败怎么办?岂不是会丢失 别急 往下看
pred.next = node;
return node;
}
}
enq(node); //注意这个函数,关键就在这里
return node;
}
private Node enq(final Node node) { //
for (;;) { //相当于while循环,知道下面设置成功才退出
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
看到上面的函数没 ,该函数会无限重试,直至成功, 到这里最终会被加入到链表末尾,之后会执行 acquireQueued()函数是自旋锁的获取过程,具体的可以看另一位老铁的博客,acquireQueued的作用我也是参考它的博看才明白的下面是链接
https://blog.csdn.net/xxcupid/article/details/51891743
另外我们知道ReentrantLock有公平锁和非公平锁,那么ReentrantLock是如何实现这个机制的呢?具体请看公平锁与非公平锁lock锁的方法了 ,对于非公平锁,lock方法
final void lock() {
if (compareAndSetState(0, 1)) //注意这里,这里先尝试设置,而不直接调用
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);//失败,则进入这里
}
对于公平锁
final void lock() {
acquire(1);//直接调用acquire方法,而在acquire方法中,如果所没有被持有只有头节点才能获取锁
}
而对于公平锁调用acquire(1)会调用此方法
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && //这一个方法是控制是否公平的关键,对比公平锁与非公平锁的tryAcquire实现你会发现只有这里不 //同 ,任何并发包能够实现公平与非公平都与该实现有关 compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
//非公平锁,的实现, final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) {//这里是主要关键0,只要是0就可以尝试获取,这是与公平锁不同的地方 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; }