¶AQS 队列同步器(二)
¶概述:
在《AQS队列同步器(一)》中对AQS的概念和基本属性了解了一下,对独占式和共享模式竞争释放锁的过程进行了了解。通过继承AQS类,JDK实现了一些很好的共享或者独占式同步工具类,包括 ReentrantLock,CountDownLatch,Semaphore,CyclicBarrier
等,接下来通过它们各自的同步器实现过程,了解AQS的实际运用。
¶辅助类:
描述: 在了解AQS的方法时,有两个类出现的机率很频繁—
LockSupport 和 Unsafe
,LockSupport
类的park和unpark方法用来在竞争锁失败时阻塞线程和释放锁时唤醒线程;Unsafe
类提供了一系列基于底层实现的CAS操作,用来对同步器的队列头尾节点,节点状态,锁状态进行设置。在了解具体同步工具类实现之前,先了解一下这两个类。LockSupport :
类说明:摘自 JDK1.8.0_191版本
用来创建锁和其他同步工具类的阻塞原语—操作系统中原始的不可分割的操作单元
该类与使用它的每一个线程都关联一个许可,当这个许可可用时,
park
方法会立刻返回,在线程中消费这个许可,否则会阻塞线程;相对的,unpark
方法会释放许可,让许可变成可用状态。很容易联想到 Semaphore 同步工具类,初始化一组许可,每次线程执行之前先请求许可,许可用完就阻塞后来线程,直到前面的线程释放许可。
park和unpark
方法提供了高效的阻塞和释放线程的方法,由于许可的存在,同时进行park和unpark
并不会导致死锁。park
方法响应中断而且也提供了超时的重载方法,不过也有可能在任意时刻“毫无原因”地返回,所有在返回之前必须在循环中重复检查条件状态是否满足。在这个场景下,park
方法表现得像优化版本“忙等待”,没有太多的自旋时间,但是必须要和unpark
方法一起使用才会生效。park和unpark
的系列方法,是为构建高性能并发模块服务的,例如park
方法在这种结构下使用:while(!process()){ LockSupport.park(this) };
只允许一个线程获取一个许可,其他任何非标准用法可能回导致非预期的结果。
方法说明:
unpark()
: 释放许可,唤醒线程代码:
1
2
3
4
5
6
7//取消线程的阻塞状态,使许可变成可用
//但是当线程没有启动时,可能不会生效
public static void unpark(Thread thread) {
if (thread != null)
//unsafe类的unpark方法
UNSAFE.unpark(thread);
}逻辑很少,判断线程非空,调用 UNSAFE.unpark(thread) 方法
//TODO