AbStractQueuedSynchronizer
类,简称AQS
,是一个来构建锁和同步器的框架,JDK1.5
开始引入了J.U.C
,大大提高了JAVA程序的并发性,而AQS
则是J.U.C
的核心,是并发类中的核心部分,他是一个基于FIFO
队列,这个队列可以构建锁或其它相关的同步基础框架
AQS
底层结构底层采用双向链表,是队列的一种实现,因此可以当做是一个队列。其中Sync queue即同步队列,它是双向链表,包括hean结点(主要用作后续的调度)与tail结点。Condition queue不是必须的,单向链表,只有在需要使用到condition的时候才会存在这个单向链表,并且可能存在多个Condition queue
AQS内部维护了一个CLH队列来管理锁,线程首先会尝试获取锁,如果失败,会将当前线程以及等待状态等信息包装成Node结点加入同步队列(Sync queue)中。接着不断循环尝试获取锁,条件是当前结点为head直接后继才会尝试,如果失败则会阻塞自己,直到自己被唤醒;而当持有锁的线程,释放锁的时候,会唤醒队列中后继线程。基于这些基础的设计和思路,JDK提供了许多基于AQS的子类。
AQS的模板方法acquire通过调用子类自定义实现的tryAcquire获取同步状态失败后->将线程构造成Node节点(创建一个独占式节点 )(addWaiter)->将Node节点添加到同步队列对尾(addWaiter)->节点以自旋的方法获取同步状态(acquirQueued)。在节点自旋获取同步状态时,只有其前驱节点是头节点的时候才会尝试获取同步状态,如果该节点的前驱不是头节点或者该节点的前驱节点是头节点单获取同步状态失败,则判断当前线程需要阻塞,如果需要阻塞则需要被唤醒过后才返回。在释放同步状态时,同步器调用tryRelease(int arg)方法释放同步状态,然后唤醒头节点的后继节点。
共享式获取与独占式获取的最主要区别在于同一时刻能否有多个线程同时获取到同步状态。通过调用acquireShared(int arg)方法可以共享式得获取同步状态。
同步器调用tryAcquireShared(int arg)方法尝试获取同步状态,其返回值为int类型,当返回值大于0时,表示能够获取同步状态。因此,在共享式获取的自旋过程中,成功获取同步状态并且退出自旋的条件就是tryAcquireShared(int arg)方法返回值大于等于0。共享式释放同步状态状态是通过调用releaseShared(int arg)方法
CountDownLatch、ReentrantReadWriteLock、Semaphore等都是共享式获取同步状态的。
关注微信公众号:【入门小站】解锁更多知识点
原文:https://www.cnblogs.com/rumenz/p/14264830.html