文档章节

Thread.AQS

脑丨残
 脑丨残
发布于 2017/05/23 22:28
字数 1001
阅读 12
收藏 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
博文 60
码字总数 23267
作品 0
西安

暂无文章

软件测试工具书籍与面试题汇总下载(持续更新)

简介 本文是https://github.com/china-testing/python-api-tesing/blob/master/books.md 的节选。 欢迎转载,转载请附带此简介,谢谢! 试题 软件测试综合面试题(高级测试)-试题.pdf 软件测试...

python测试开发人工智能安全
12分钟前
0
0
java.sql.SQLException: Io 异常: The Network Adapter could not establish the connection 解决

有个项目使用的log4j进行日志记录的,同时也是用log4j中的数据库配置直接把相应级别的日志直接插入oracle。 在把项目部署的另一个内网环境时候,把项目的其他配置都改了,唯独log4j中的数据库...

哥本哈根的小哥
22分钟前
0
0
耗时 2 年,用 8.5 万块乐高积木最牛复刻 Apple Park

简评:国外大佬复刻 Apple Park,看了一下细节,确实厉害!只有你想不到,没有乐高拼不起来的,有没有乐高大神挑战一下? 苹果公园以各种各样的方式鼓舞人心,让人感兴趣。从建筑、可持续性和...

极光推送
23分钟前
0
0
记一次查找Hdfs磁盘占用空间比实际存储文件大4倍的原因

在一次主备namenode发生切换后,重启datanode节点,发现磁盘空间很大,想清理一下磁盘, 通过命令Hdfs dfs -du -h --max-depth=1 / 发现实际文件的大小只有8g,通过du -h --max-depth=1 /ha...

PageYi
50分钟前
4
0
阿里云推荐引擎使用教程

产品概述: 推荐引擎(Recommendation Engine,以下简称RecEng,特指阿里云推荐引擎)是在阿里云计算环境下建立的一套推荐服务框架,目标是让广大中小互联网企业能够在这套框架上快速的搭建满...

mcy0425
51分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部