不以文害辞,不以辞害志;以意逆志,是为得之。——孟子
最近在看ThreadPoolExecutor类的源码。我发现其中一个重要的子类Woker继承自AbstractQueuedSynchronizer(简称AQS)。AQS帮助Woker类轻松实现一个非重入的排它锁。不看不知道一看吓一跳,竟然有11个类继承自AQS,而且这些类都是并发包下面使用频率很高的类。这足以说明这个类的含金量,值得认真研究一下。
源码注释
为实现依赖于等待队列的阻塞锁和相关同步器(信号量、事件)提供一个框架。此类的设计目标是成为依靠单个原子整形数值来表示状态的大多数同步器的基础。子类必须定义更改此状态的方法,并定义哪种状态对于此对象意味着被获取或被释放。实现这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但是只有原子更新整形值的应用方法(涉及到同步)被追踪,以下是这三个应用方法 getState()、setState(int) 和compareAndSetState(int, int)。
应该将子类定义为非公共内部帮助类,可用它们来实现其内部类的同步属性。AbstractQueuedSynchronizer类 没有实现任何同步接口。而是定义了诸如acquireInterruptibly(int) 之类的方法,在适当的时候可以通过具体的锁和相关同步器调用它们,以达到同步的目的。
此类支持默认的独占 模式和共享 模式任何一种方式,也可以同时支持两种模式。处于独占模式下,其他线程不可能再成功获取锁。在共享模式下,多个线程获可能成功获得锁。此类只是机械地感知到在共享模式下成功获取某一锁时,下一个等待线程(如果存在)也必须确定是否可以成功获取该锁。处于不同模式下的等待线程可以共享相同的 FIFO 队列。通常,子类只支持其中一种模式,但两种模式都可以在ReadWriteLock 中发挥作用。只支持独占模式或者只支持共享模式的子类不必定义未使用模式的方法。
使用
描述
AQS简核心是通过一个共享变量来同步状态,变量的状态由子类去维护,而AQS框架做的是:
- 线程阻塞队列的维护
- 线程阻塞和唤醒。
共享变量的修改都是通过CAS操作完成的。AbstractQueuedSynchronizer类是一个典型的模板方法类。它的主要方法是acquire和release。 acquire方法用来获取锁,返回true说明线程获取成功继续执行,一旦返回false则线程加入到等待队列中,等待被唤醒,release方法用来释放锁。 一般来说实现的时候这两个方法被封装为lock和unlock方法。
下面这4个方法由子类去实现:
1 | protected boolean tryAcquire(int arg) |
ThreadPoolExecutor.Worker
下面就来看一下以下Worker的实现
1 |
|