AQS源码深入分析之独占模式-ReentrantLock锁特性详解 (5)

不光上面的cancelAcquire方法会调用到本方法,unlock方法中也会调用本方法来唤醒下一个节点:

1 /** 2 * AbstractQueuedSynchronizer: 3 * 唤醒下一个可以被唤醒的节点 4 */ 5 private void unparkSuccessor(Node node) { 6 int ws = node.waitStatus; 7 /* 8 如果当前节点状态是SIGNAL或者PROPAGATE,将其CAS设置为初始状态0 9 因为后续会唤醒第一个被阻塞的节点,所以这里节点的状态如果还是SIGNAL就不正确了, 10 因为SIGNAL表示的是下一个节点是阻塞状态 11 */ 12 if (ws < 0) 13 compareAndSetWaitStatus(node, ws, 0); 14 15 //s是当前节点的下一个节点 16 Node s = node.next; 17 //如果下一个节点为null,或者状态为CANCELLED 18 if (s == null || s.waitStatus > 0) { 19 s = null; 20 //从CLH队列的尾节点向前遍历到该节点为止,找到该节点往后第一个处于正常阻塞状态的节点 21 for (Node t = tail; t != null && t != node; t = t.prev) 22 if (t.waitStatus <= 0) 23 s = t; 24 } 25 //如果找到了或者遍历之前的下一个节点本身就处于正常阻塞状态的话,就唤醒它 26 if (s != null) 27 LockSupport.unpark(s.thread); 28 } 3.7 unlock方法

ReentrantLock的unlock方法:

1 /** 2 * ReentrantLock: 3 */ 4 public void unlock() { 5 sync.release(1); 6 } 7 8 /** 9 * AbstractQueuedSynchronizer: 10 */ 11 public final boolean release(int arg) { 12 //释放一次锁,如果没有可重入锁的话,就进入到下面的if条件中 13 if (tryRelease(arg)) { 14 Node h = head; 15 /* 16 如果头节点存在且下一个节点处于阻塞状态的时候就唤醒下一个节点 17 因为在之前加锁方法中的shouldParkAfterFailedAcquire方法中,会将前一个节点的状态置为SIGNAL 18 所以这里判断waitStatus不为0就意味着下一个节点是阻塞状态,然后就可以唤醒了 19 如果为0就没有必要唤醒,因为下一个节点本身就是处于非阻塞状态 20 */ 21 if (h != null && h.waitStatus != 0) 22 unparkSuccessor(h); 23 return true; 24 } 25 return false; 26} 27 28 /** 29 * ReentrantLock: 30 * 第13行代码处: 31 */ 32 protected final boolean tryRelease(int releases) { 33 //c = state - 1 34 int c = getState() - releases; 35 //如果当前线程不是上锁时的线程,则抛出异常 36 if (Thread.currentThread() != getExclusiveOwnerThread()) 37 throw new IllegalMonitorStateException(); 38 boolean free = false; 39 //如果减完1后的state是0的话,也就是没有可重入锁发生的情况,则可以将独占锁拥有者设置为null 40 if (c == 0) { 41 free = true; 42 setExclusiveOwnerThread(null); 43 } 44 //设置state为减完1后的结果 45 setState(c); 46 return free; 47 } 4 公平锁

ReentrantLock的公平锁和非公平锁实现上的区别寥寥无几,只有lock方法和tryAcquire方法是不同的(包括unlock解锁方法的实现都是一样的),也就是FairSync类中覆写的两个方法。所以下面就来看一下这两个方法的实现。

4.1 lock方法 1 /** 2 * ReentrantLock: 3 */ 4 final void lock() { 5 /* 6 可以看到在公平锁模式下,只是调用了acquire方法而已。而在非公平锁模式下,会首先执行 7 compareAndSetState,如果CAS失败才调用acquire方法。这个意思也就是说:非公平锁 8 模式下的每个线程在加锁时会首先尝试加一下锁,去赌一下此时是否释放锁了。如果释放了, 9 那么此时的这个线程就能抢到锁,相当于插队了(这也就是“非公平”的含义)。如果没抢到就 10 继续去CLH队列中排队。而公平锁模式下的每个线程加锁时都只是会去乖乖排队而已 11 */ 12 acquire(1); 13 } 4.2 tryAcquire方法 1 /** 2 * ReentrantLock: 3 * 可以看到公平锁模式下的tryAcquire方法和非公平锁模式下的nonfairTryAcquire方法的区别 4 * 仅仅是多调用了一次hasQueuedPredecessors方法,其他都是一样的。所以下面就来看一下该 5 * 方法的实现 6 */ 7 protected final boolean tryAcquire(int acquires) { 8 final Thread current = Thread.currentThread(); 9 int c = getState(); 10 if (c == 0) { 11 if (!hasQueuedPredecessors() && 12 compareAndSetState(0, acquires)) { 13 setExclusiveOwnerThread(current); 14 return true; 15 } 16 } else if (current == getExclusiveOwnerThread()) { 17 int nextc = c + acquires; 18 if (nextc < 0) 19 throw new Error("Maximum lock count exceeded"); 20 setState(nextc); 21 return true; 22 } 23 return false; 24 } 4.3 hasQueuedPredecessors方法

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfypy.html