队列同步器(AbstractQueuedSynchronizer),简称同步器或AQS。它为实现锁提供了一个框架,内部维护了一个先进先出的队列,以及state状态变量!ReentrantLock、ReentrantReadWriteLock、Semaphore(信号量)、CountDownLatch、公平锁、非公平锁、ThreadPoolExecutor等都和AQS有关!
AQS是用来构建锁,或其他同步组件的基础框架:
内部通过一个int类型的成员变量state,来控制同步状态:
当state=0时,则说明没有任何线程占有共享资源的锁;
当state=1时,则说明有线程目前正在使用共享变量,其他线程必须加入同步队列进行等待。
AQS通过内部类Node构成FIFO的同步队列来完成线程获取锁的排队工作;
同时利用内部类ConditionObject构建等待队列,当Condition调用wait()方法后,线程将会加入等待队列中;而当Condition调用signal()方法后,线程将从等待队列转移到同步队列中进行锁竞争。
注意,这里涉及到两种队列:
一种的同步队列,当线程请求锁而等待后,将加入同步队列等待;
另一种则是等待队列(可有多个),通过Condition调用await()方法释放锁后,将加入等待队列。
在锁的实现类中会聚合同步器,然后利用同步器实现锁的语义:
锁是面向使用者的,它定义了使用者与锁交互的接口,隐藏了实现细节!
同步器面向的是锁的实现者——Daug Lea、自定义同步器,它简化了锁的实现方式,屏蔽了同步状态管理、线程排队、等待/唤醒等底层操作!
从AQS的类名称和修饰上来看,这是一个抽象类,所以从设计模式的角度来看,同步器一定是基于模版模式来设计的,使用者需要继承同步器,实现自定义同步器,并重写指定方法,随后将同步器组合在自定义的同步组件中,并调用同步器的模版方法,而这些模版方法又回调使用者重写的方法。
想理解上面这句话,只需要知道下面两个问题:
哪些是自定义同步器可重写的方法?
哪些是抽象同步器提供的模版方法?
自定义同步器实现的相关方法,只是为了通过修改state字段,来实现多线程的独占模式或者共享模式。自定义同步器需要实现以下方法(ReentrantLock需要实现的方法如下,并不是全部):
| 方法名 | 描述 |
|---|---|
| protected boolean isHeldExclusively() | 该线程是否正在独占资源。只有用到Condition才需要去实现它。 |
| protected boolean tryAcquire(int arg) | 独占方式。arg为获取锁的次数,尝试获取资源,成功则返回True。 |
| protected boolean tryRelease(int arg) | 独占方式。arg为释放锁的次数,尝试释放资源,成功则返回True。 |
| protected int tryAcquireShared(int arg) | 共享方式。arg为获取锁的次数,尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。 |
| protected boolean tryReleaseShared(int arg) | 共享方式。arg为释放锁的次数,尝试释放资源,如果释放后允许唤醒后续等待结点返回True,否则返回False。 |
1.Java AQS队列同步器以及ReentrantLock的应用
2.从ReentrantLock的实现看AQS的原理及应用
原文:https://www.cnblogs.com/chenzufeng/p/14543408.html