首先,阅读AQS作者留下的注释:
AQS旨在提供一个框架,用于实现依赖于一个FIFO线程队列的同步和锁机制,这些机制的特点都是依赖于一个单一的原子int值来表示状态。子类必须实现该类的protected修饰的方法,以及赋予这个int值具体表示何种状态,来实现自己想要的锁或同步机制。子类可以维护其他状态字段,但是只有使用getState、setState和compareAndSetState方法修改的表示状态的int值才是有效的。
子类应当被定义为非public的内部辅助类,用于实现其包围类的同步属性。AQS并没有提供一个实现同步机制的接口,而是通过提供acquireInterruptly这种小的实现某种策略的锁的过程,供具体的实现锁的选择。(个人对于这句话的理解就是,我AQS不给你提供一个成品,也为了不让你自己造轮子,因此我给你一个框架,这个框架里面有各种半成品,你可以根据你的需要来组合和加工这些半成品来实现你自己想要的成品)
这个类支持默认独占方式和共享方式的一种(也可以都支持),比如有些资源是互斥访问的,单一时间只能由一个线程使用,又有一些资源可能同时有一个以上的线程共同使用,这两类资源的访问都通过AQS提供的半成品实现出来。而对于AQS自己来说,它自己是不理解这些差异的,需要你自己赋予它意义。在实现共享资源访问时(这里解释一下作者想表达的共享资源应该是操作系统中初始信号量>=2的情形,当semaphore=1时,这种资源就是互斥资源,同一时刻只有由一个线程持有)。其实个人感觉跟操作系统的信号量机制提供的semaphore和P、V操作差不多,通过PV操作你可以实现同步或者互斥问题。但是P、V操作本身并不知道你在具体实现哪种情况。
通常情况下,实现子类只支持其中一种模式(独占模式和共享模式),但两种模式都可以发挥作用,例如在ReadWriteLock中。只支持独占或共享模式的子类不需要定义支持未使用模式的方法。(这段话的理解是,通常实现的锁机制只能要么当作独占模式用,要么当作共享模式用。如果你的资源和环境只是独占模式,你就不需要去实现共享模式)
这一段介绍了ConditionObject适用于实现独占模式的锁或同步机制。这个等看完了整段介绍再看吧。
之后给出了可以加工实现下列方法实现你自己的锁。
tryAcquire()
tryRelease()
tryAcquireShared()
tryReleaseShared()
isHeldExclusively()
而后作者又说到,从AOS类继承过来的方法对于诊断占有互斥资源的线程很有用。可以用这些监控和诊断工具可以帮助用户确定哪些线程持有锁。
之后又说,虽然我们的队列是FIFO队列,但是在实现的时候最终的策略可能并不是FIFO的,比如给出了非公平锁的样例。
今日更新,总体读完文档和观察ReentrantLock对于AQS继承之后的两种实现来看,我们要做的无非就是:
tryAcquire():执行完此方法后是否拿到了临界资源的访问权,拿到了就是true,没拿到就是false,我们只用管什么时候给予访问权,什么时候不给予访问权,至于之后要做的工作AQS类已经帮我们实现好了:入队过程和阻塞线程。
观察ReentrantLock的实现源码,Sync类继承了AQS类且仍然为抽象类(lock和tryAcquire方法还没有实现),而又有NonfairSync类和FairSync两种实现,分别为公平锁和非公平锁。非公平锁:就是先请求是否能得到临界资源访问权,如果未得到再进入等待队列。公平锁:先检查等待队列是否为空,若为空再检查是否能拿到访问权,若等待队列不为空,则直接进入等待队列。而这两种锁都在tryAcquire方法中实现了可重入锁的逻辑(若当前持有临界资源的线程再次请求锁,则可以继续获得锁),因此ReentrantLock为可重入锁。ReentrantLock获得锁的方式为使用CAS操作来改变state变量的值。
Sync类中对于线程竞争以及取得锁的条件相关代码如下:
Sync类对于AQS的proteced修饰的方法实现了tryRelease和isHeldExclusively两个方法。isHeldExclusively方法一般用于实现当前临界资源是否已经有其他线程访问,适合独占模式下 的状态判断。Sync类将此方法用于线程没得到锁的情况下,判断这个线程是否就是持有锁的线程,若是,则就视为该线程取得了锁返回给acquire的if判断语句,用以让AQS帮助我们做之后的工作(入队列以及阻塞线程)。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
而ReentrantLock还提供了tryLock方法,此方法用于:如果当前能拿到锁就拿,拿不到就算了(没有入队和阻塞的操作)。
在学操作系统的时候,我们遇到了哲学家问题、吸烟者问题、生产者-消费者问题等,在解决这些问题的时候,我们不止使用了一个信号量,而是用多个信号量解决复杂的多线程问题,而AQS如果只有state变量来应对高并发场景不一定能解决所有问题,因此就引入了ConditionObject类。