线程是如何阻塞以及唤醒的呢?
这里要提出LockSupport类,其有两个重要的方法:
//唤醒线程(底层实现依赖于操作系统)
public static void unpark(Thread thread);
//阻塞当前线程(底层实现依赖于操作系统)
public static void park(Object blocker)
unpark函数可以先于park调用。unpark函数为线程提供“许可(permit)”,线程调用park函数则等待“许可”,如果已经有许可,那么线程会马上再继续运行。
await()
CountDownLatch的await()方法,其执行过程是:
1.addWaiter
创建一个SHARED节点
对象,并加入到队列尾部(如果在这之前没有任何节点,要先创建一个head节点)
2.执行等待
2.1 获取步骤1节点的上一个节点。
2.2 如果上一个节点是head节点,且已经没有执行中的任务,阻塞结束,返回。
2.3 如果不是,await方法所在的线程被阻塞(LockSupport.park(this); )。
countDown()
调用tryReleaseShared方法对计数减一(使用CAS乐观锁),如果还有未完成的任务,则结束countDown方法。如果全部任务执行完成,则调用unparkSuccessor方法解除阻塞(LockSupport.unpark(s.thread); )。