文档章节

Thread.AQS

脑丨残
 脑丨残
发布于 2017/05/23 22:28
字数 1001
阅读 11
收藏 0
点赞 0
评论 0

AQS

  • AbstractQueuedSynchronizer队列同步器,Lock接口实现的核心,可自定义同步器。
     *      +------+  prev +-----+       +-----+
     * head |      | <---- |     | <---- |     |  tail
     *      +------+       +-----+       +-----+
  • CLH锁实现图,将每个线程构造成Node节点,加入链表,新加入线程在列表队列最后,每次头结点获取到所,后续节点继续获取锁。
  • AQS暴露操作方法,隐藏实现细节,集成AQS,重写获取锁方法,可自定义同步锁。
  • 内部通过voliate修饰的int变量,unsafe方法提供的compareAndSet方法提供同步,逐步包装成同步队列,同步锁。
  • 原理总结,用AQS的volatile的同步特性,设置int锁数量,unsafe对象的CAS同步设置方法,构造同步队列,最后unsafe的park,unpark直接操作线程挂起释放。
static final class Node {
       
        static final Node SHARED = new Node();
        static final Node EXCLUSIVE = null;
        static final int CANCELLED =  1;
 
        static final int SIGNAL    = -1;
     
        static final int CONDITION = -2;
  
        static final int PROPAGATE = -3;
        volatile int waitStatus;
        volatile Node prev;
        volatile Node next;
        volatile Thread thread;
    
        Node nextWaiter;
 
    }
  • 以Lock的实现Reentranlock为例
public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    private final Sync sync;
    //实现AQS重写锁
    //Lock的所有操作,通过代理内部类调用AQS,先看非公平锁
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;
        abstract void lock();
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
    }
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        //2. sync的非公平实现,快速调用父类AQS的CAS设置state是,如果失败,进入acquire构造Node节点,加入CLK
        //
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        
        //3. AQS的acruird,tryAcquire交给子类自定实现,addWaiter加入CLK节点,acquireQueued,所有节点自旋,获取同步状态
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    //1. 外部调用Lock
    public void lock() {
        sync.lock();
    }
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
    public Condition newCondition() {
        return sync.newCondition();
    }
}

    //4. AQS中的实现,tryAcquire交给子类
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
      //5. ReentranLock里Sync非公平锁实现
      final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //获取AQS中state
            int c = getState();
            if (c == 0) {
                //AQS的CAS同步设置state,并设置持有线程
                if (compareAndSetState(0, acquires)) {
                    //设置持有线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //可重入关键,同一线程可重复获取锁
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    //6. 加入CLK链表尾部,通过AQS,CAS设置tail节点,构造链表见自定容器Stack
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            //快速设置tail,如果失败进入enq
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
    //死循环设置尾节点,直到成功,以死循环的方式,同步设置tail节点
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }
    //7. 最后,每个构造的节点,都以自旋的方式,获取前一节点,如果前一节点是头节点,并且获取到锁,把当前自己设置成头结点,获的锁。
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //parkAndCheckInterrupt 调用LockSupport挂起线程,进入阻塞状态
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    //unlock,调用AQS释放
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
            //LockSupport的unparking,释放线程挂起状态    
            unparkSuccessor(h);
            return true;
        }
        return false;
    }
     //1. 交给子类实现
     protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

© 著作权归作者所有

共有 人打赏支持
脑丨残
粉丝 8
博文 59
码字总数 23267
作品 0
西安

暂无相关文章

收集自网络的wordpress 分页导航的代码教程(全网最全版)

wordpress 分页导航是用来切换文章的一个功能,添加了 wordpress 分页导航后,用户即可自由到达指定的页面数浏览分类文章,而这样的一个很简单功能却有很多朋友在用插件:WP-PageNavi,插件的...

Rhymo-Wu ⋅ 40分钟前 ⋅ 0

微服务 WildFly Swarm 入门

Hello World 就像前面章节中的其他框架一样,我们希望添加一些基本的 Hello-world 功能,然后在其上逐步添加更多的功能。让我们从在我们的项目中创建一个 HolaResources 开始。您可以使用您的...

woshixin ⋅ 47分钟前 ⋅ 0

Maven的安装和Eclipse的配置

1. 下载Maven 下载地址 2. 解压压缩包,放到自己习惯的硬盘中 此处我将其放到了 D:\Tools 目录下。 3. 配置环境变量 右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量。 在系统变量中新建,变...

影狼 ⋅ 55分钟前 ⋅ 0

python pip使用国内镜像的方法

国内源 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://......

良言 ⋅ 55分钟前 ⋅ 0

对于url变化的spa应该如何使用微信jssdk

使用vue单页面碰上微信jssdk config验证失败的坑。第一次成功 之后切换页面全部失败,找到了解决方法,第一次验证成功后保存验证信息 切换页面时验证信息直接拿来用,加一个wx.error() 失败时...

孙冠峰 ⋅ 今天 ⋅ 0

Spring Cloud Gateway 一般集成

SCF发布,带来很多新东西,不过少了点教程,打开方式又和以前的不一样,比如这个SCG,压根就没有入门指导,所以这里写一个,以备后用。 一、集成 pom.xml <dependency> <groupI...

kut ⋅ 今天 ⋅ 0

建造模式

《JAVA与模式》之建造模式

Cobbage ⋅ 今天 ⋅ 0

WePY框架开发的小程序如何在微信web开发者工具中运行起来

一、首先需要安装node.js,安装步骤如下: 首先下载安装包 https://nodejs.org/en/download/ 点击下载相应的zip版本 然后将文件夹解压到任意目录 比如我这里解压到了:C:\Program Files\node...

Helios51 ⋅ 今天 ⋅ 0

使用EnumSet 代替位域(32)

1、位域(Bit field):使用or 运算将几个常量合并到一个集合中 位操作,可以有效地执行 AND 、OR 这样的位操作 但是 位域比int 常量枚举缺点更多 2、java.util 包里面的EnumSet 类是有效的替...

职业搬砖20年 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部