Java多线程系列--深入理解AQS(三)

上一篇帖了很多AQS的代码,可以看出AQS的实现思路很简单,就是提供了获取acquire和释放操作release,提供了

1. 可中断和不可中断的版本

2. 可定时和不可定时的版本

3. 独享和共享的版本

看过之前实现各种自旋锁系列的同学应该知道,在自旋锁的实现中,获取锁和释放锁操作的逻辑基本如下:

自旋锁获取锁操作

while 状态不允许获取锁 {

      自旋

}

进入锁之前设置某些状态

自旋锁释放锁操作

设置释放锁的状态

if (允许后续线程获取锁){

    通知后续线程获取锁

}

而AQS的获取和释放操作也基本是这个逻辑,但是区别是它使用了阻塞操作,而不是自旋操作

AQS获取操作 acquire

while (状态不允许获取操作){

    if(需要阻塞获取请求){

          如果当前线程不在同步队列中,那么将其插入队列

          阻塞当前线程

    }else{

          返回失败

    }

}

可能更新同步器状态

如果线程位于同步队列,则将其移出队列

返回成功

}

AQS释放操作 release

更新同步器状态

if(新的状态允许某个被阻塞的线程获取成功){

      解除队列中一个或多个线程的阻塞状态

}

要实现AQS的获取和释放功能,至少需要考虑三方面

1. 共享状态的原子修改,因为是在并发情况下

2. 线程的阻塞和唤醒,使用了Unsafe的park机制

3. 队列的管理,使用了两个队列,同步队列和条件队列。同步队列进行获取和释放操作,条件队列进行阻塞和唤醒操作

AQS抽象类负责管理上述的三个方面,而具体的同步器实现类则需要根据基类暴露出的状态相关的方法实现tryAcquire()和tryRelease()方法,以控制accquire和release操作。当状态满足时,tryAccquire方法要返回true,当新的状态允许后续线程获取时,tryRelease要返回true。另外这两类方法都支持一个int的状态参数,这个参数用于传递同步操作需要的状态,不是所有的同步器都需要。

AQS提供了一个上层的基类提供了构建同步器的底层构件,可以方便地使用它来创建各种类型的同步器。后面会聊聊juc包种的同步器是如何使用AQS来构建的,理解了AQS之后,我们也可以方便地利用它来创建自定义的同步器解决实际问题。

发布了169 篇原创文章 · 获赞 6 · 访问量 3487

猜你喜欢

转载自blog.csdn.net/weixin_42073629/article/details/104788480