您当前的位置: 首页 >  Java

小志的博客

暂无认证

  • 0浏览

    0关注

    1217博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java并发多线程编程——AQS(AbstractQueuedSynchronizer 抽象的队列同步器)详解

小志的博客 发布时间:2021-04-22 21:28:06 ,浏览量:0

目录
    • 一、AQS的理解
    • 二、AQS定义的两种资源共享方式
    • 三、AQS的使用
    • 四、同步器的实现是ABS核心(state资源状态计数)
    • 五、ReentrantReadWriteLock实现独占和共享两种方式
    • 六、AQS中的方法摘要(以下内容摘自JDK1.8版本在线中文文档)
    • 七、JDK1.8版本在线中文文档

一、AQS的理解
  • AQS是AbstractQueuedSynchronizer的简称,JDK1.5以后才出现,属于java.util.concurrent.locks包下的类。
  • AbstractQueuedSynchronizer类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch。 在这里插入图片描述
  • 它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。这里volatile是核心关键词,具体volatile的语义,在此不述。state的访问方式有三种:
    • getState()
    • setState()
    • compareAndSetState()
二、AQS定义的两种资源共享方式

1、 Exclusive独占资源-ReentrantLock

  • Exclusive(独占,只有一个线程能执行,如ReentrantLock)

2、Share共享资源-Semaphore/CountDownLatch

  • Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。
三、AQS的使用
  • AQS只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现,AQS这里只定义了一个接口,具体资源的获取交由自定义同步器去实现了(通过state的get/set/CAS)之所以没有定义成abstract, 是 因 为 独 占 模 式 下 只 用 实 现tryAcquire-tryRelease, 而 共 享 模 式 下 只 用 实 现tryAcquireShared-tryReleaseShared。如果都定义成abstract,那么每个模式也要去实现另一模式下的接口。不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法:

  • tryAcquire(int): 独占方式。尝试获取资源,成功则返回true,失败则返回false

  • tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。

  • tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。

  • tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。

  • isHeldExclusively() :该线程是否正在独占资源。只有用到condition才需要去实现它。

四、同步器的实现是ABS核心(state资源状态计数)
  • 同步器的实现是ABS核心,以ReentrantLock为例,state初始化为0,表示未锁定状态。A线程lock()时,会调用tryAcquire()独占该锁并将state+1。此后,其他线程再tryAcquire()时就会失败,直到A线程unlock()到state=0(即释放锁)为止,其它线程才有机会获取该锁。当然,释放锁之前,A线程自己是可以重复获取此锁的(state会累加),这就是可重入的概念。但要注意,获取多少次就要释放多么次,这样才能保证state是能回到零态的。
  • 以CountDownLatch以例,任务分为N个子线程去执行,state也初始化为N(注意N要与线程个数一致)。这N个子线程是并行执行的,每个子线程执行完后countDown()一次,state会CAS减1。等到所有子线程都执行完后(即state=0),会unpark()主调用线程,然后主调用线程就会从await()函数返回,继续后余动作。
五、ReentrantReadWriteLock实现独占和共享两种方式
  • 一般来说,自定义同步器要么是独占方法,要么是共享方式,他们也只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。但AQS也支持自定义同步器同时实现独占和共享两种方式,如ReentrantReadWriteLock。
六、AQS中的方法摘要(以下内容摘自JDK1.8版本在线中文文档) 序号返回值方法名称及解释1voidacquire(int arg) 以独占模式获取对象,忽略中断。2voidacquireInterruptibly(int arg) 以独占模式获取对象,如果被中断则中止。3voidacquireShared(int arg) 以共享模式获取对象,忽略中断。4voidacquireSharedInterruptibly(int arg) 以共享模式获取对象,如果被中断则中止。5protected booleancompareAndSetState(int expect, int update) 如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。6Collection < thread>getExclusiveQueuedThreads() 返回包含可能正以独占模式等待获取的线程 collection。7ThreadgetFirstQueuedThread() 返回队列中第一个(等待时间最长的)线程,如果目前没有将任何线程加入队列,则返回 null. 在此实现中,该操作是以固定时间返回的,但是,如果其他线程目前正在并发修改该队列,则可能出现循环争用。8Collection < thread>getQueuedThreads() 返回包含可能正在等待获取的线程 collection。9intgetQueueLength() 返回等待获取的线程数估计值。10Collection< Thread>getSharedQueuedThreads() 返回包含可能正以共享模式等待获取的线程 collection。11protected intgetState() 返回同步状态的当前值。12Collection< Thread>getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition) 返回一个 collection,其中包含可能正在等待与此同步器有关的给定条件的那些线程。13intgetWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition) 返回正在等待与此同步器有关的给定条件的线程数估计值。14booleanhasContended() 查询是否其他线程也曾争着获取此同步器;也就是说,是否某个 acquire 方法已经阻塞。15booleanhasQueuedThreads() 查询是否有正在等待获取的任何线程。16booleanhasWaiters(AbstractQueuedSynchronizer.ConditionObject condition) 查询是否有线程正在等待给定的、与此同步器相关的条件。17protected booleanisHeldExclusively() 如果对于当前(正调用的)线程,同步是以独占方式进行的,则返回 true。18booleanisQueued(Thread thread) 如果给定线程的当前已加入队列,则返回 true。19booleanowns(AbstractQueuedSynchronizer.ConditionObject condition) 查询给定的 ConditionObject 是否使用了此同步器作为其锁。20booleanrelease(int arg) 以独占模式释放对象。21booleanreleaseShared(int arg) 以共享模式释放对象。22protected voidsetState(int newState) 设置同步状态的值。23StringtoString() 返回标识此同步器及其状态的字符串。24protected booleantryAcquire(int arg) 试图在独占模式下获取对象状态。25booleantryAcquireNanos(int arg, long nanosTimeout) 试图以独占模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。26protected inttryAcquireShared(int arg) 试图在共享模式下获取对象状态。27booleantryAcquireSharedNanos(int arg, long nanosTimeout) 试图以共享模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。28protected booleantryRelease(int arg) 试图设置状态来反映独占模式下的一个释放。29protected booleantryReleaseShared(int arg) 试图设置状态来反映共享模式下的一个释放。 七、JDK1.8版本在线中文文档

https://www.matools.com/api/java8 在这里插入图片描述

关注
打赏
1661269038
查看更多评论
立即登录/注册

微信扫码登录

0.0427s