Condition

用于实现多线程之间的通信;

核心方法: await() 和 notify();

await() ;

将当前线程(此时线程一定是获取到🔐的)加入 等待队列;线程变为等待状态

  1. public final void await() throws InterruptedException {
  2. if (Thread.interrupted()) //表示 await 允许被中断
  3. throw new InterruptedException();
  4. Node node = addConditionWaiter(); //创建一个新的节点,节点状态为 condition,采用的数据结构仍然是链表
  5. int savedState = fullyRelease(node); //释放当前的锁,得到锁的状态,并唤醒 AQS 队列中的一个线程
  6. int interruptMode = 0;
  7. //如果当前节点没有在同步队列上,即还没有被 signal,则将当前线程阻塞
  8. while (!isOnSyncQueue(node)) { //判断这个节点是否在 AQS 队列上,第一次判断的是 false,因为前面已经释放锁了
  9. LockSupport.park(this); //通过 park 挂起当前线程
  10. if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
  11. break;
  12. }
  13. // 当这个线程醒来,会尝试拿锁, 当 acquireQueued 返回 false 就是拿到锁了.
  14. // interruptMode != THROW_IE -> 表示这个线程没有成功将 node 入队,但 signal 执行了 enq 方法让其入队了.
  15. // 将这个变量设置成 REINTERRUPT.
  16. if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
  17. interruptMode = REINTERRUPT;
  18. // 如果 node 的下一个等待者不是 null, 则进行清理,清理 Condition 队列上的节点. // 如果是 null ,就没有什么好清理的了.
  19. if (node.nextWaiter != null) // clean up if cancelled
  20. unlinkCancelledWaiters();
  21. // 如果线程被中断了,需要抛出异常.或者什么都不做
  22. if (interruptMode != 0)
  23. reportInterruptAfterWait(interruptMode);
  24. }

addConditionAwait()

这个方法的主要作用是把当前线程封装成 Node,添加到等待队列。这里的队列不再是双向链表,而是单向链表

signal()

等待唤醒AQS、等待队列状态图

点击查看【processon】

countDownLatch

  1. private Node addConditionWaiter() {
  2. Node t = lastWaiter;
  3. // 如 果 lastWaiter 不 等 于 空 并 且waitStatus 不等于 CONDITION 时,把冲好这个节点从链表中移除
  4. if (t != null && t.waitStatus != Node.CONDITION) {
  5. unlinkCancelledWaiters();
  6. t = lastWaiter; }
  7. //构建一个 Node,waitStatus=CONDITION。这里的链表是一个单向的,所以相比 AQS 来说会简单很多
  8. Node node = new
  9. Node(Thread.currentThread(),
  10. Node.CONDITION);
  11. if (t == null)
  12. firstWaiter = node;
  13. else
  14. t.nextWaiter = node;
  15. astWaiter = node;
  16. return node;
  17. }

Semapore

cyclicBarrir

参考