聊聊高并发(二十三)解析java.util.concurrent各个组件(五) 深入理解AQS(三)
2014-11-07 10:10
656 查看
这篇对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的状态参数,这个参数用于传递同步操作需要的状态,不是所有的同步器都需要。
关于获取操作和释放操作的具体算法细节,可以参考Doug Lea的这篇论文,详细分析了获取操作和释放操作的设计细节 The juc Synchronizer Framework中文翻译版
AQS提供了一个上层的基类提供了构建同步器的底层构件,可以方便地使用它来创建各种类型的同步器。后面会聊聊juc包种的同步器是如何使用AQS来构建的,理解了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的状态参数,这个参数用于传递同步操作需要的状态,不是所有的同步器都需要。
关于获取操作和释放操作的具体算法细节,可以参考Doug Lea的这篇论文,详细分析了获取操作和释放操作的设计细节 The juc Synchronizer Framework中文翻译版
AQS提供了一个上层的基类提供了构建同步器的底层构件,可以方便地使用它来创建各种类型的同步器。后面会聊聊juc包种的同步器是如何使用AQS来构建的,理解了AQS之后,我们也可以方便地利用它来创建自定义的同步器解决实际问题。
相关文章推荐
- 聊聊高并发(二十二)解析java.util.concurrent各个组件(四) 深入理解AQS(二)
- 聊聊高并发(二十四)解析java.util.concurrent各个组件(六) 深入理解AQS(四)
- 聊聊高并发(二十四)解析java.util.concurrent各个组件(六) 深入理解AQS(四)
- 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一)
- 聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁
- 聊聊高并发(二十六)解析java.util.concurrent各个组件(八) 理解CountDownLatch闭锁
- 聊聊高并发(三十九)解析java.util.concurrent各个组件(十五) 理解ExecutorService接口的设计
- 聊聊高并发(三十)解析java.util.concurrent各个组件(十二) 理解CyclicBarrier栅栏
- 聊聊高并发(三十一)解析java.util.concurrent各个组件(十三) 理解Exchanger交换器
- 聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁
- 聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁
- 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore
- 聊聊高并发(三十八)解析java.util.concurrent各个组件(十四) 理解Executor接口的设计
- 聊聊高并发(三十八)解析java.util.concurrent各个组件(十四) 理解Executor接口的设计
- 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore
- 聊聊高并发(三十九)解析java.util.concurrent各个组件(十五) 理解ExecutorService接口的设计
- 聊聊高并发(二十)解析java.util.concurrent各个组件(二) 12个原子变量相关类
- 聊聊高并发(四十二)解析java.util.concurrent各个组件(十八) 任务的批量执行和CompletionService
- 聊聊高并发(四十)解析java.util.concurrent各个组件(十六) ThreadPoolExecutor源代码分析
- 聊聊高并发(二十)解析java.util.concurrent各个组件(二) 12个原子变量相关类