当前位置:   article > 正文

JUC之ReentrantLock(二)

JUC之ReentrantLock(二)

ReentrantLock.unLock():锁的释放

 

  1. public void unlock() {
  2. sync.release(1);//AQS
  3. }

 AbstractQueuedSynchronizer.release()

 

 

  1. public final boolean release(int arg) {
  2. if (tryRelease(arg)) {//尝试释放锁,子类实现
  3. Node h = head;
  4. if (h != null && h.waitStatus != 0)
  5. unparkSuccessor(h);//唤醒后继节点
  6. return true;
  7. }
  8. return false;
  9. }

    若 tryRelease(arg)释放锁成功(state==0);则考虑唤醒AQS中的下一个节点,前提:队列不为空,AQS队列的头结点需要锁(waitStatus!=0),如果头结点需要锁,就开始检测下一个继任节点是否需要锁操作。

waitStatus含义

 

 

ReentrantLock.Sync.tryRelease(int releases)

 

  1. protected final boolean tryRelease(int releases) {
  2. int c = getState() - releases;
  3. if (Thread.currentThread() != getExclusiveOwnerThread())//持有锁的线程不是当前线程,抛出异常。(线程锁只有拥有锁的线程才能释放)
  4. throw new IllegalMonitorStateException();
  5. boolean free = false;
  6. if (c == 0) {//state = 0:表示当前线程已经释放了锁,锁处于空闲状态.因为ReetrantLock可重入,maybe c>0
  7. free = true;
  8. setExclusiveOwnerThread(null);
  9. }
  10. setState(c);
  11. return free;
  12. }

AbstractQueuedSynchronizer.unparkSuccessor(Node node)

  1. private void unparkSuccessor(Node node) {
  2. /*
  3. * If status is negative (i.e., possibly needing signal) try
  4. * to clear in anticipation of signalling. It is OK if this
  5. * fails or if status is changed by waiting thread.
  6. */
  7. int ws = node.waitStatus;
  8. if (ws < 0)//当前node已经释放锁了,状态设置为0
  9. compareAndSetWaitStatus(node, ws, 0);
  10. /*
  11. * Thread to unpark is held in successor, which is normally
  12. * just the next node. But if cancelled or apparently null,
  13. * traverse backwards from tail to find the actual
  14. * non-cancelled successor.
  15. */
  16. //从头结点的下一个节点开始寻找继任节点,当且仅当继任节点的waitStatus<=0才是有效继任节点,否则将这些waitStatus>0(也就是CANCELLED的节点)从AQS队列中剔除
  17. //这里并没有从head->tail开始寻找,而是从tail->head寻找最后一个有效节点。
  18. //解释在这里 http://www.blogjava.net/xylz/archive/2010/07/08/325540.html#377512
  19. Node s = node.next;
  20. if (s == null || s.waitStatus > 0) {
  21. s = null;
  22. for (Node t = tail; t != null && t != node; t = t.prev)
  23. if (t.waitStatus <= 0)
  24. s = t;
  25. }
  26. if (s != null)
  27. LockSupport.unpark(s.thread);
  28. }

 

 

  1. 这里再一次把acquireQueued的过程找出来。对比unparkSuccessor,一旦头节点的继任节点被唤醒,那么继任节点就会尝试去获取锁(在acquireQueued中node就是有效的继任节点,p就是唤醒它的头结点),如果成功就会将头结点设置为自身,并且将头结点的前任节点清空,这样前任节点(已经过时了)就可以被GC释放了。
  2. final boolean acquireQueued(final Node node, int arg) {
  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. return interrupted;
  11. }
  12. if (shouldParkAfterFailedAcquire(p, node) &&
  13. parkAndCheckInterrupt())
  14. interrupted = true;
  15. }
  16. } catch (RuntimeException ex) {
  17. cancelAcquire(node);
  18. throw ex;
  19. }
  20. }

 参考:http://www.blogjava.net/xylz/archive/2010/07/08/325540.html

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/567084
推荐阅读
相关标签
  

闽ICP备14008679号