首页 > 代码库 > ReentrantLock是如何阻塞等待线程的?

ReentrantLock是如何阻塞等待线程的?

 1 public class Test_Lock {
 2     static ReentrantLock lock = new ReentrantLock();
 3     static class Runner implements Runnable {
 4         @Override
 5         public void run() {
 6             lock.lock(); 
 7             System.out.println(Thread.currentThread().getName());
 8             lock.unlock();
 9         }
10 
11     }
12     public static void main(String[] args) {
13         lock.lock();
14         Thread t1 = new Thread(new Runner());
15         t1.start();
16         Thread t2 = new Thread(new Runner());
17         t2.start();
18         lock.unlock();
19         System.out.println(lock.getHoldCount());
20     }
21 }

新建一个ReentrantLock对象,主线程第一次调用ReentrantLock/lock -> NonfairSync/lock

1 final void lock() {
2     if (compareAndSetState(0, 1))
3         setExclusiveOwnerThread(Thread.currentThread()); //主线程成功获取锁。
4     else
5         acquire(1); //子线程等待
6 }

子线程1调用ReentrantLock/lock -> NonfairSync/lock -> AbstractQueuedSynchronizer/acquire(1)

1 public final void acquire(int arg) {
2     if (!tryAcquire(arg) &&
3         acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
4         selfInterrupt();
5 }

1) -> NonfairSync/tryAcquire -> Sync/nonfairTryAcquire
主线程已经获得锁,所以返回false。

 1 final boolean nonfairTryAcquire(int acquires) {
 2     final Thread current = Thread.currentThread();
 3     int c = getState();
 4     if (c == 0) {
 5         if (compareAndSetState(0, acquires)) {
 6             setExclusiveOwnerThread(current);
 7             return true;
 8         }
 9     }
10     else if (current == getExclusiveOwnerThread()) {
11         int nextc = c + acquires;
12         if (nextc < 0) // overflow
13             throw new Error("Maximum lock count exceeded");
14         setState(nextc);
15         return true;
16     }
17     return false;
18 }

2) -> AbstractQueuedSynchronizer/addWaiter -> AbstractQueuedSynchronizer/enq
把子线程加入等待队列,此时队列为空,所以直接enq(node)。

 1 private Node addWaiter(Node mode) {
 2     Node node = new Node(Thread.currentThread(), mode);
 3     // Try the fast path of enq; backup to full enq on failure
 4     Node pred = tail;
 5     if (pred != null) {
 6         node.prev = pred;
 7         if (compareAndSetTail(pred, node)) {
 8             pred.next = node;
 9             return node;
10         }
11     }
12     enq(node);
13     return node;
14 }

enq函数是死循环里面包含一个if else分支,
先进if分支,创建了一个没有数据的节点作为头结点,加入队列,
再入else分支,使用CAS将当前节点插入队列尾部(如果由于多线程的原因导致执行失败,则会继续下一次循环插入节点,直到插入成功)。
最后返回插入成入的节点。

 1 private Node enq(final Node node) {
 2     for (;;) {
 3         Node t = tail;
 4         if (t == null) { // Must initialize
 5             if (compareAndSetHead(new Node()))
 6                 tail = head;
 7         } else {
 8             node.prev = t;
 9             if (compareAndSetTail(t, node)) {
10                 t.next = node;
11                 return t;
12             }
13         }
14     }
15 }

 

3) -> AbstractQueuedSynchronizer/acquireQueued
该方法就是不停地判断阻塞线程的条件是否满足,一旦满足就阻塞线程。
还是个死循环,死循环内部包含两个if,第一个if,p == head 但是tryAcquire会失败(同1),所以第一个if不执行。
第二个if,-> AbstractQueuedSynchronizer/shouldParkAfterFailedAcquire
判断前驱节点的状态值(此时为0),所以会执行CAS设置前驱节点的状态为Node.SIGNAL(-1),并返回 false。
进入下一轮循环,再次 -> AbstractQueuedSynchronizer/shouldParkAfterFailedAcquire,此时返回true。

 1 final boolean acquireQueued(final Node node, int arg) {
 2     boolean failed = true;
 3     try {
 4         boolean interrupted = false;
 5         for (;;) {
 6             final Node p = node.predecessor();
 7             if (p == head && tryAcquire(arg)) {
 8                 setHead(node);
 9                 p.next = null; // help GC
10                 failed = false;
11                 return interrupted;
12             }
13             if (shouldParkAfterFailedAcquire(p, node) &&
14                 parkAndCheckInterrupt())
15                 interrupted = true;
16         }
17     } finally {
18         if (failed)
19             cancelAcquire(node);
20     }
21 }
22 
23 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
24     int ws = pred.waitStatus;
25     if (ws == Node.SIGNAL)
26         /*
27          * This node has already set status asking a release
28          * to signal it, so it can safely park.
29          */
30         return true;
31     if (ws > 0) {
32         /*
33          * Predecessor was cancelled. Skip over predecessors and
34          * indicate retry.
35          */
36         do {
37             node.prev = pred = pred.prev;
38         } while (pred.waitStatus > 0);
39         pred.next = node;
40     } else {
41         /*
42          * waitStatus must be 0 or PROPAGATE.  Indicate that we
43          * need a signal, but don‘t park yet.  Caller will need to
44          * retry to make sure it cannot acquire before parking.
45          */
46         compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
47     }
48     return false;
49 }

 

然后 -> AbstractQueuedSynchronizer/parkAndCheckInterrupt
此时线程就阻塞在死循环中了。

1 private final boolean parkAndCheckInterrupt() {
2     LockSupport.park(this); 
3     return Thread.interrupted();
4 }

那么线程是如何被唤醒的呢?

ReentrantLock是如何阻塞等待线程的?