码迷,mamicode.com
首页 > 其他好文 > 详细

AbstractQueuedSynchronizer类(AQS)

时间:2020-01-10 00:40:24      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:prot   color   gate   ctf   node   lock   null   help   current   

AbstractQueuedSynchronizer抽象同步队列是一个抽象类,简称AQS,是实现同步器的基础组件,并发包中锁的底层就是使用AQS实现的

AQS的数据结构:逻辑结构:双向队列,存储结构:链式存储,所以包含头尾节点head、tail及节点Node。

一、Node(静态内部类)

1、变量与构造方法

        //标记线程是获取共享资源时被阻塞挂起后放入AQS队列的
        static final Node SHARED = new Node();
        //标记线程是获取独占资源时被挂起后放入AQS队列的
        static final Node EXCLUSIVE = null;

        //waitStatus == 1:表示线程已取消
        static final int CANCELLED =  1;
        //waitStatus == -1:线程需要被唤醒(与LockSupport的关联许可LockSupport.unpark)
        static final int SIGNAL    = -1;
        //waitStatus == -2:线程在条件队列中等待
        static final int CONDITION = -2;
        //waitStatus == -3释放共享资源时需要通知其他节点
        static final int PROPAGATE = -3;

        //状态
        volatile int waitStatus;

        //前一个节点
        volatile Node prev;

        //
        volatile Node next;

        //后一个节点
        volatile Thread thread;

        //
        Node nextWaiter;

        Node() {    //无参构造方法  创建头结点或者共享模型节点
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter 等待队列节点
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition 条件队列节点
            this.waitStatus = waitStatus;
            this.thread = thread;
        }

2.方法;只有两个方法

        /**
         * Returns true if node is waiting in shared mode.
         */判断是否是共享模式下的节点
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * Returns previous node, or throws NullPointerException if null.
         * Use when predecessor cannot be null.  The null check could
         * be elided, but is present to help the VM.
         * 返回pre 为空时空指针异常
         * @return the predecessor of this node
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

二、AQS

1.变量和构造方法

    //双链表头节点  延迟初始化  只能setHead修改 头结点waitStatus != Node.CANCELLED
    private transient volatile Node head;

    //双链表尾节点  延迟初始化 只能enq()入队时修改
    private transient volatile Node tail;

    //The synchronization state.同步锁状态
    private volatile int state;

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long stateOffset;
    private static final long headOffset;
    private static final long tailOffset;
    private static final long waitStatusOffset;
    private static final long nextOffset;

    static {
        try {
            stateOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
            headOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
            waitStatusOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("waitStatus"));
            nextOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("next"));

        } catch (Exception ex) { throw new Error(ex); }
    }

    protected AbstractQueuedSynchronizer() { }

2.方法

1).Node enq(Node node):入队方法,头尾节点的初始化;及尾插法建立链表入队。是private方法,必有封装方法

    /**
     * 节点入队,包含头尾节点初始化
     */
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;//初始化,tail == head == new Node();
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;//标准的尾插法建立链表
                }
            }
        }
    }

2. Node addWaiter(Node node):enq方法的封装,但还是private方法,封装方法分为两类:共享模式,独占模式

    /**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // 尾节点不为空时,初次入队尝试跳过enq方法直接入队,如果CAS失败,调用enq入队,enq方法会无限重试CAS for(;;)
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

共享资源模式:

1)void doAcquireShared(int arg):

    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)//尝试获取共享资源,成功直接返回,失败入阻塞队列
            doAcquireShared(arg);
    }

    /**
     * 共享模式下获取资源,中断导致park返回中断后还原, 另有doAcquireSharedInterruptibly方法,中断导致park返回时抛出异常,结束线程
     * @param arg the acquire argument
     */
    private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);//共享资源Node节点插入阻塞队列
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
//前驱节点是头节点时,尝试获取共享资源成功后检查Node.waiterStatus<0释放资源,还原中断标志
if (p == head) { int r = tryAcquireShared(arg); if (r >= 0) { setHeadAndPropagate(node, r); p.next = null; // help GC if (interrupted) selfInterrupt(); failed = false; return; } }
if (shouldParkAfterFailedAcquire(p, node) &&//设置Node.waiterStatus == Node.SIGNAL parkAndCheckInterrupt())//LockSupport.park阻塞线程,当返回时判断是否中断引起的返回 interrupted = true; } } finally { if (failed) cancelAcquire(node); } }


AbstractQueuedSynchronizer类(AQS)

标签:prot   color   gate   ctf   node   lock   null   help   current   

原文地址:https://www.cnblogs.com/wqff-biubiu/p/12173900.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!