4.从AbstractQueuedSynchronizer(AQS)说起——AQS结语

Posted CoderBuff

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4.从AbstractQueuedSynchronizer(AQS)说起——AQS结语相关的知识,希望对你有一定的参考价值。

  前两节的内容《2.从AbstractQueuedSynchronizer(AQS)说起(1)——独占模式的锁获取与释放》 《3.从AbstractQueuedSynchronizer(AQS)说起(2)——共享模式的锁获取与释放》对AQS同步器已经有了一个大致的了解,从独占模式和共享模式来解析了AQS的两个基本方面,一个是同步状态的获取,另外一个是同步状态的释放,这是AQS最基本的特性,前面两节都是以阻塞的形式获取同步状态,但实际上AQS还能超时等待获取同步状态,或者非阻塞的方式获取同步状态。

  以下是AQS锁定义的所有情况下同步状态的获取与释放(粗体为前两节已经讨论过),有了前两篇的解析,实际上剩余的方法几乎已经是换汤不换药。在这里就不再代码的具体分析,而我希望是在真正解读其子类的时候再返回来解析。 

 

AbstractQueuedSynchronizer 

public final void acquire(int arg) 

独占模式下阻塞获取同步状态,成功获取则返回,失败则进入同步队列等待。(例:ReentrantLock.lock) 

public final void acquireInterruptibly(int arg) 

该方法与acquire类似,唯一不同的是如果当前线程被中断,该方法会抛出InterruptedException并返回,也就是说如果当前线程不被中断则和acquire一样。(例:ReentrantLock.lockInterruptibly 

public final boolean tryAcquireNanos(int arg, long nanosTimeOut) 

该方法在acquireInterruptibly的基础上增加了超时限制,如果当前线程在超时时间内获取到同步状态则返回true,获取不到则返回false。(例:ReentrantLock.tryLock) 

public final acquireShared(int arg) 

共享模式下阻塞获取同步状态,成功获取则返回,失败则进入同步队列。(例:ReentrantReadWriteLock.unlock) 

public final acquireSharedInterruptibly(int arg) 

与acquireShared不同是此方法响应中断,与acquireInterruptibly类似,不同是的此方法是在共享模式下。(例:ReentrantReadWriteLock.lockInterruptibly) 

public final tryAcquireSharedNanos(int arg, long nanos) 

在acquireSharedInterruptibly基础上增加了超时限制,同样是在共享模式下。(例:ReentrantReadWriteLock.tryAcquireSharedNanos) 

public final boolean release(int arg) 

独占模式下释放同步状态,释放之后会将同步队列中的第一个包含的线程唤醒 

public final boolean releaseShared(int arg) 

共享模式下释放同步状态 

  以下是AQS中给提供的获取同步状态等相关的方法: 

 

AbstractQueuedSynchronizer 

public final boolean hasQueuedThreads() 

同步队列中是否有等待线程 

public final boolean hasContended() 

查询是否其他线程也曾争则获取此同步器,也就是说acquire是否已经阻塞,是则返回true 

public final Thread getFirstQueuedThread() 

返回当前同步队列中的第一个线程,米有则返回null。 

public final boolean isQueued(Thread thread) 

线程是否已经在等待队列中,是则返回true。 

final boolean apparentlyFirstQueuedIsExclusive() 

(包级可见)同步队列中第一个等待节点是否为独占模式 

public final boolean hasQueuedPredecessors() 

查询是否有其他线程获取同步状态的时间大于当前线程,用于公平锁的实现。 

public final int getQueueLength() 

返回同步队列的估计长度,该方法用于监视系统状态,而非同步控制。 

public final Collection<Thread> getQueuedThreads() 

获取同步队列线程集合,同样是一个估计值。 

public final Collection<Thread> getWaitingThreads(ConditionObject condition) 

获取在等等队列中的线程集合,估计值。 

public final Collection<Thread> getExclusiveQueuedThreads() 

获取同步队列中独占模式线程集合,估计值。 

public final Collection<Thread> getSharedQueuedThreads() 

获取同步队列中共享模式线程集合,同估计值。 

final isOnSyncQueue(Node node) 

当前节点是否在sync等待队列中 

  以上方法或多或少再其子类有用到,具体的实现都不复杂,我们在这里也不对其一一做出分析,而是在具体分析到AQS的子类时,我们再回过头来看方法的实现。 

最后我们再来看看子类可以重写的方法,这些方法在前两节中有提到过: 

 

AbstractQueuedSynchronizer 

protected boolean tryAcquire(int arg) 

子类可实现在独占模式下获取同步状态的具体方法。 

protected boolean tryRelease() 

子类可实现在独占模式下释放同步状态的具体方法。 

protected int tryAcquireShared(int arg) 

子类可实现在共享模式下获取同步状态的具体方法。 

protected int tryReleaseShared() 

子类可实现在共享模式下释放同步状态的具体方法。 

protected boolean isHeldExclusively() 

当前同步器是否在独占模式下被线程占用,一般表示该方法是否被当前线程所独占。 

  Java并发包的第一个源码解读并不顺利,起初是想以Lock开头,但发现AQS不甚了解,继而决定从AQS入手。而真正从AQS入手过后发现很多原理及方法并不熟悉,又想从其子类之一ReentrantLock$Sync由下往上,但发现还是动不了脑子和笔,无奈陷入了停滞。最终决定由上往下进行解读,有的地方需要子类或者其他类做解释的时候要么跳过,要么一句话带过。在查找AQS的相关资料时,我发现其实源代码就是一个很好的“老师”,作者实际上已经将其实现的原理和过程以及设计都已经描述在其中,但又出现一个问题,注释都是英文,很多地方看不懂。网上有关AQS的解读都没有成套成体系的资料,于是开始将注意力转向书籍,先是查阅《Java并发编程实战》也许对于外国人来说源码中注释里已经写得很清楚的东西就不用再阐述了,而我正是需要最最基础的“注释翻译”。再查阅《Thinking in Java》更是没有我想要的东西,再看看其他的书均没有。突然想起有一个国人写的书《Java并发编程的艺术》,看了看目录决定入手,这本书的确对我入门Java并发包的源码有很大的帮助,尽管它不想《Java并发编程实战》这么经典、耐看,但是它作为入门级却有很大的帮助,文中的不少分析就是结合这本书以及源码才让我得以比较顺利的开展第一个Java并发包的AbstractQueuedSynchronizer源码解读。源码的阅读也许就是这样,跳过来跳过去,这个类继承,那个类实现,相互交叉耦合,很难一下就能读懂作者所要想表达的意思,坚持读下去,一定会豁然开朗。 

 

以上是关于4.从AbstractQueuedSynchronizer(AQS)说起——AQS结语的主要内容,如果未能解决你的问题,请参考以下文章

xwiki从7.4.4升级至8.4.4

MongoDB从4.4.2~4.4.4升级存严重Bug

如何从 Hibernate 4.3.4.Final 中检索 sessionFactory?

Python:如何从 4 字节字节数组中获取 4 字节大小的整数?

将 MongoDB 从 2.6 升级到 4.2.6

WPF MVVM从入门到精通4:命令和事件