博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
3.从AbstractQueuedSynchronizer(AQS)说起(2)——共享模式的锁获取与释放
阅读量:7049 次
发布时间:2019-06-28

本文共 2412 字,大约阅读时间需要 8 分钟。

  在上节中解析了AbstractQueuedSynchronizer(AQS)中独占模式对同步状态获取和释放的实现过程。本节将会对共享模式的同步状态获取和释放过程做一个解析。上一节提到了独占模式和共享模式的区别,最主要的区别就是在同一时刻能否有多个线程同时获取到同步状态。

  1).共享模式同步状态的获取

  这个方法同独占模式获取同步状态的acquire方法一样,同样也是一个模板方法,我们简要回顾一下独占模式下获取同步状态的acquire方法:

//AbstractQueuedSynchronizer#acquirepublic final void acquire(int arg) {    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))    //获取锁(tryAcquire)->构造节点(addWaiter)->加入队列(addWaiter)->自旋获取锁(acquireQueued)    selfInterrupt();    //中断当前线程}
//AbstractQueuedSynchronizer#acquireSharedpublic final void acquireShared(int arg) {    if (tryAcquireShared(arg)) //获取锁,由子类具体实现    doAcquireShared(arg);}private void doAcquireShared(int arg) {    final Node node = addWaiter(Node.SHARED);    boolean failed = true;    try {        boolean interrupted = false;        for (;;) {            final Node p = node.predecessor();            if (p == head) {                int r = tryAcquireShared(arg);            if (r >= 0) {                setHeadAndPropagate(node, r);                p.next = null;                if (inerrupted)                     selfInterrupt();                failed = false;                return;            }        }        if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())        interrupted = true;    }} finally {    if (failed)        cancelAcquire(arg);        }}

共享模式下获取同步状态的自旋过程和独占模式大致相同,从代码实现角度来看不同的是共享模式下把线程构造节点加入队列,以及在获取同步状态后中断当前线程都放到了同一个方法里doAcquireShared。共享模式同样也是只有在是其前驱节点是头结点的时候才会尝试获取同步状态,调用tryAcquireShared获取同步状态成功后会返回大于等于0的数,这个时候将会执行setHeadAndPropagate方法,这个方法首先会将当前获取同步状态的这个线程置为头节点(同独占模式一样),但在将当前线程置为头节点过后,又做了一部分操作,其代码如下:

private void setHeadAndPropagate(Node node, int propagate) {    Node h = head;    setHead(node);    //将当前获取到同步状态的线程节点置为头节点     if (propagate > 0 || h == null || h.waitStatus < 0) {    //唤醒后继节点    Node s = node.next;    if (s == null || s.isShared())         doReleaseShared();    //唤醒后继节点,因为是共享模式,所以允许多个线程同时获取同步状态    }}

  在doReleaseShared方法中,首先便利队列中的所有节点,如果节点状态为SIGNAL,则把SIGNAL状态置为0(初始状态),并调用unparkSuccessor把该节点的后继节点唤醒,如果该节点的状态为0,则把状态置为PROPAGATE。

 2).共享模式同步状态的释放

  该方法的实现同独占模式类似,也是一个模板方法,具体的释放实现由子类自定义,在成功释放同步状态后将会唤醒后继节点:

public final boolean releaseShared(int arg) {    if (tryReleaseShared(arg)) {    //释放同步状态        doReleaseShared();    //唤醒后继节点        return true;    }    return false;}

  以上就是AQS中的共享模式对同步状态的获取与释放,在有了独占模式的分析过后,对共享模式的分析就显得要轻松得多。下一节将会继续探讨AbstractQueuedSynchronizer类中具体的一些细节问题。

 

转载地址:http://zndol.baihongyu.com/

你可能感兴趣的文章
单元测试问题一览
查看>>
打造 Laravel 优美架构 谈可维护性与弹性设计
查看>>
新手路:用node js和mongodb数据库创建AJAX API接口
查看>>
如何获得C4C里某个code字段对应的描述信息
查看>>
elasticsearch -- 基础入门 -- 请求体查询 -- 最重要的查询
查看>>
MCPlayerKit 易用的播放组件,通用播放器
查看>>
报错xxxx of undefined
查看>>
配置HTTPS,公钥证书有效期短怎么办?
查看>>
重新学习web后端开发-004-了解http响应
查看>>
js判断微信内核浏览器
查看>>
原生JS发请求
查看>>
数字签名信息安全
查看>>
项目打包优化
查看>>
力扣(LeetCode)417
查看>>
199. Binary Tree Right Side View
查看>>
PHP_SELF变量解析和重复路径解决
查看>>
JS每日一题:什么情况下适合使合vuex?Vuex使用中有几个步骤?
查看>>
原来实现GCP用客户端登录这么简单啊
查看>>
JS每日一题: 请简述一下vuex实现原理
查看>>
从 TodoList 中学父子组件通信
查看>>