线程1->加锁->释放锁&阻塞->线程2->加锁->唤醒线程1->释放锁->线程1->再次加锁

线程1执行await

image.png

  1. public final void await() throws InterruptedException {
  2. if (Thread.interrupted())
  3. throw new InterruptedException();
  4. Node node = addConditionWaiter();
  5. int savedState = fullyRelease(node);
  6. int interruptMode = 0;
  7. while (!isOnSyncQueue(node)) {
  8. LockSupport.park(this);
  9. if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
  10. break;
  11. }
  12. if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
  13. interruptMode = REINTERRUPT;
  14. if (node.nextWaiter != null) // clean up if cancelled
  15. unlinkCancelledWaiters();
  16. if (interruptMode != 0)
  17. reportInterruptAfterWait(interruptMode);
  18. }
  1. Node node = addConditionWaiter();封装一个Condition的Node

image.png

  1. int savedState = fullyRelease(node);保存当前node节点的一个状态,同时更改aqs里面的state和ownerThread的值(还原到最开始无锁的状态),同时要唤醒另外因抢占锁导致入队阻塞的线程Thread1

image.png
image.png
执行完upark,第二个线程的lock阶段就不会卡住了。就要开始加锁了。
image.png

  1. !isOnSyncQueue(node);判断当前这个node是不是Conditon类型的,如果是Condition类型的Node就要走while代码块的东西。
  2. LockSupport.park(this);挂起当前线程,这边代码直接卡住

image.png

线程2执行signal

此时,线程2已经加锁成功了
image.png
执行signal
image.png

Node first = firstWaiter;

image.png

doSignal(first);

开始唤醒线程1

  1. private void doSignal(Node first) {
  2. do {
  3. //不用太关心
  4. if ( (firstWaiter = first.nextWaiter) == null)
  5. lastWaiter = null;
  6. first.nextWaiter = null;
  7. }
  8. //重点执行transferForSignal
  9. while (!transferForSignal(first) &&
  10. (first = firstWaiter) != null);
  11. }
  12. final boolean transferForSignal(Node node) {
  13. /*
  14. * If cannot change waitStatus, the node has been cancelled.
  15. */
  16. if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
  17. return false;
  18. /*
  19. * Splice onto queue and try to set waitStatus of predecessor to
  20. * indicate that thread is (probably) waiting. If cancelled or
  21. * attempt to set waitStatus fails, wake up to resync (in which
  22. * case the waitStatus can be transiently and harmlessly wrong).
  23. */
  24. Node p = enq(node);
  25. int ws = p.waitStatus;
  26. if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
  27. LockSupport.unpark(node.thread);
  28. return true;
  29. }
  1. !compareAndSetWaitStatus(node, Node.CONDITION, 0);这个结果一定是false,因为当前这个线程1Node节点的类型就是Condition类型的,因此cas能成功

image.png

  1. Node p = enq(node); enq方法,很熟悉了就是把当前这个Node加入队列中,如果没有队列就创建一个。

image.png

  1. if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
    LockSupport.unpark(node.thread); 通过判断,把线程1唤醒
  2. 回到线程1卡住的代码,就会继续往下走,最后把线程1Node设置成一个空的Node当作head Node

image.png
image.png