AbstractQueuedSynchronizer 详解

Posted loveer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AbstractQueuedSynchronizer 详解相关的知识,希望对你有一定的参考价值。

package java.util.concurrent.locks;

基本介绍

AbstractQueuedSynchronizer(队列同步器)可以看作是并发包(java.util.concurrent)的基础框架。

AQS是一个抽象类,当构建一个同步组件的时候,需要定义一个子类继承AQS,应用了模板方法设计模式


模板模式由一个抽象类和一个实现类组成,抽象类中主要有三类方法:

    模板方法:实现了算法主体框架,供外部调用。里面会调用原语操作和钩子操作。

    原语操作:即定义的抽象方法,子类必须重写。

    钩子操作:和原语操作类似,也是供子类重写的,
        区别是钩子操作子类可以选择重写也可以选择不重写,如果不重写则使用抽象类默认操作,通常是一个空操作或抛出异常。

AQS中可供子类重写的钩子操作

方法名称 描述
boolean tryAcquire(int arg) 独占式获取同步状态,成功返回true,失败返回false。
boolean tryRelease(int arg) 独占式释放同步状态,成功返回true,失败返回false。
int tryAcquireShared(int arg) 共享式获取同步状态,获取成功则返回值>=0
boolean tryReleaseShared(int arg) 共享式释放同步状态,成功返回true,失败返回false。
boolean isHeldExclusively() 判断同步器是否在独占模式下被占用,一般用来表示同步器是否被当前线程占用

模板方法

子类重写相关钩子操作后,AQS中提供的模板方法才能正常调用

方法 描述
void acquire(int arg) 独占式获取同步状态,该方法会调用子类重写的tryAcquire(int arg),如果tryAcquire返回true则该方法直接返回,否则先将当前线程加入同步队列的尾部,然后阻塞当前线程
void acquireInterruptibly(int arg) 和acquire类似,只是当线程获取同步状态失败被阻塞后,可以响应中断,收到中断后将会取消获取同步状态
boolean tryAcquireNanos(int arg, long nanosTimeout) 在acquireInterruptibly的基础上加了超时限制,如果在超时时间内获取到同步状态返回true,否则返回false
boolean release(int arg) 独占式释放同步状态,该方法会在释放同步状态后将第一个节点(对应刚刚释放同步状态的线程)的后继节点对应的线程唤醒。
void acquireShared(int arg) 共享式获取同步状态,该方法会调用子类重写的tryAcquireShared(int arg),如果tryAcquireShared返回true则该方法直接返回,否则先将当前线程加入同步队列的尾部,然后阻塞当前线程
void acquireSharedInterruptibly(int arg) 和acquireShared类似,只是当线程获取同步状态失败被阻塞后,可以响应中断,收到中断后将会取消获取同步状态
boolean tryAcquireSharedNanos(int arg, long nanosTimeout) 在acquireSharedInterruptibly的基础上加了超时限制,如果在超时时间内获取到同步状态返回true,否则返回false
boolean releaseShared(int arg) 共享式的释放同步状态

源码分析

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable 

    private static final long serialVersionUID = 7373984972572414691L;

    protected AbstractQueuedSynchronizer()  

    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;

        final boolean isShared() 
            return nextWaiter == SHARED;
        

        final Node predecessor() 
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        

        Node() 

        Node(Node nextWaiter) 
            this.nextWaiter = nextWaiter;
            THREAD.set(this, Thread.currentThread());
        

        Node(int waitStatus) 
            WAITSTATUS.set(this, waitStatus);
            THREAD.set(this, Thread.currentThread());
        

        final boolean compareAndSetWaitStatus(int expect, int update) 
            return WAITSTATUS.compareAndSet(this, expect, update);
        

        final boolean compareAndSetNext(Node expect, Node update) 
            return NEXT.compareAndSet(this, expect, update);
        

        final void setPrevRelaxed(Node p) 
            PREV.set(this, p);
        

        private static final VarHandle NEXT;
        private static final VarHandle PREV;
        private static final VarHandle THREAD;
        private static final VarHandle WAITSTATUS;
        static 
            try 
                MethodHandles.Lookup l = MethodHandles.lookup();
                NEXT = l.findVarHandle(Node.class, "next", Node.class);
                PREV = l.findVarHandle(Node.class, "prev", Node.class);
                THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
                WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
             catch (ReflectiveOperationException e) 
                throw new ExceptionInInitializerError(e);
            
        
    

    private transient volatile Node head;

    private transient volatile Node tail;

    private volatile int state;

    protected final int getState() 
        return state;
    

    protected final void setState(int newState) 
        state = newState;
    

    protected final boolean compareAndSetState(int expect, int update) 
        return STATE.compareAndSet(this, expect, update);
    

    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;

以上是关于AbstractQueuedSynchronizer 详解的主要内容,如果未能解决你的问题,请参考以下文章

ReentrantLock原理源码详解

一行一行源码分析清楚 AbstractQueuedSynchronizer

Java并发-- AQS 原理