juc之AQS源码二
共享方式
juc之AQS源码一中讲了独占方式的源码,这里分析共享方式的源码。
acquireShared共享方式获取资源
acquireShared方法
acquireShared方法是共享模式下线程获取共享资源的顶层入口。它会获取指定量的资源,获取成功则直接返回,获取失败则进入等待队列,直到获取到资源为止,整个过程忽略中断。
1 | public final void acquireShared(int arg) { |
这里tryAcquireShared()依然需要自定义同步器去实现。但是AQS已经把其返回值的语义定义好了:负值代表获取失败;0代表获取成功,但没有剩余资源;正数表示获取成功,还有剩余资源,其他线程还可以去获取。
所以函数流程如下:
- tryAcquireShared()尝试获取资源,成功则直接返回。
- 失败则通过doAcquireShared()进入等待队列,直到获取到资源为止才返回。
doAcquireShared方法
此方法用于将当前线程加入等待队列尾部休息,直到其他线程释放资源唤醒自己,自己成功拿到相应量的资源后才返回。
1 | private void doAcquireShared(int arg) { |
这个方法和acquireQueued方法很相似,只不过这里将补充中断的位置搬进来了。
setHeadAndPropagate方法
这个方法在自己苏醒的同时,如果条件符合(比如还有剩余资源),还会去唤醒后继结点,毕竟是共享模式!
1 | private void setHeadAndPropagate(Node node, int propagate) { |
总结
基本流程:
tryAcquireShared()
尝试获取资源,成功则直接返回。- 失败则通过
doAcquireShared()
进入等待队列park()
,直到被unpark()/interrupt()
并成功获取到资源才返回。整个等待过程也是忽略中断的。
跟acquire的流程相似,多了个自己拿到资源后,还回去唤醒后面的线程。
releaseShared共享方式释放资源
releaseShared方法
此方法是共享模式下线程释放共享资源的顶层入口。
它会释放指定量的资源,如果成功释放且允许唤醒等待线程,它会唤醒等待队列里的其他线程来获取资源。
1 | public final boolean releaseShared(int arg) { |
释放掉资源后,唤醒后继。
跟独占模式下的release()相似,但有一点稍微需要注意:独占模式下的tryRelease()在完全释放掉资源(state=0)后,才会返回true去唤醒其他线程,这主要是基于独占下可重入的考量;而共享模式下的releaseShared()则没有这种要求(只要有释放,就回去唤醒),共享模式实质就是控制一定量的线程并发执行,那么拥有资源的线程在释放掉部分资源时就可以唤醒后继等待结点。
doReleaseShared方法
这个方法用于唤醒后继节点。
1 | private void doReleaseShared() { |
参考文献 & 鸣谢
相关文章