队列同步器(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