澳门网络娱乐游戏平台-澳门电子游戏娱乐网址-官方直营

【澳门网上网址平台】Java并发功底框架AbstractQueuedSynchronizer初探(ReentrantLock的兑现剖判卡塔尔

要点解释

AbstractQueuedSynchronizer简单称谓AQS,它是java.util.concurrent包下CountDownLatch/FutureTask/ReentrantLock/RenntrantReadWriteLock/Semaphore完毕的底蕴,所以深切驾驭AQS非经常有至关重要。

AQS通过内部贯彻的FIFO等待队列来形成资源获取线程的等候职业,借使当前线程获取能源失利,AQS则会将前段时间线程以致等待情形等消息构变成三个Node构造的节点,并将其出席等待队列中,同期会堵塞当前线程;当别的获取到财富的线程释放具有的财富时,则会把等待队列节点中的线程唤醒,使其再一次尝试获得相应财富。

AbstractQueuedSynchronizer是兑现Java并发类库的三个根底框架,Java中的各类锁(雷内ntrantLock, ReentrantReadWriteLock卡塔尔以至一块工具类(Semaphore, CountDownLatch卡塔尔(英语:State of Qatar)等大多都以基于AbstractQueuedSynchronizer完成的。AbstractQueuedSynchronizer 平时简单称谓AQS,Abstract表示她是三个抽象类,Queued代表他是依据先进先出 FIFO 等待队列达成的,Synchronizer表示她是三个同步器。

简介

JDK1.5从今今后,Java提供了Lock甚至众多用于的现身开采的类(举例:ReentrantLock、CountDownLatch、CyclicBarrier等),而那一个类的完毕超级多都是基于AbstractQueuedSynchronizer(队列同步器,简单的称呼AQS卡塔尔国来兑现。

AbstractQueuedSynchronizer内部有多个int变量表示的联合状态(同步状态通过getState setState compareAndSetState来爱惜,同一时间那四个艺术能够确认保障线程安全卡塔尔国,以致三个FIFO双向队列,一般称这么些队列为同步队列。当线程获取财富(竞争同步状态卡塔尔国失败就能够走入同步队列排队。

AQS是个抽象类(可是那么些抽象类中并不曾抽象方法),同步组件平日经过维护AQS的继续子类来促成。AQS既扶助独自占领地获取同步状态,又帮衬分享地获得同步状态,进而完结差异门类的组件。

AQS是基于模板方法,同步组件供给一连同步器同仁一视写钦赐的点子,随后将同步器组合在自定义同步组件的贯彻中,并调用同步器提供的模版方法,而那些模板方法将会调用使用者重写的章程。以下是AQS中可重写的措施。

  • protected boolean tryAcquire(int arg卡塔尔(英语:State of Qatar) : 独自占领式获取同步状态,试着得到,成功再次回到true,反之为false;
  • protected boolean tryRelease(int arg卡塔尔(قطر‎:独自据有式释放同步状态,等待中的其余线程当时将有空子收获到二头状态;
  • protected int tryAcquireShared(int arg卡塔尔:分享式获取同步状态,重回值大于等于0,代表获取成功;反之获得失利;
  • protected boolean tryReleaseShared(int arg卡塔尔:分享式释放同步状态,成功为true,失利为false;
  • protected boolean isHeldExclusively(卡塔尔(英语:State of Qatar) : 是或不是在独自占领格局下被线程占用。

那个类在AQS中的暗中同意类都是回顾的抛出UnsupportedOperationException格外
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }

源码分析

AbstractQueuedSynchronizer源码相比较长,这里只拆解分析首要的效劳代码。首先,先看一下它里面定义的Node类的代码。

static final class Node {
        //声明共享模式下的等待节点
        static final Node SHARED = new Node();
        //声明独占模式下的等待节点
        static final Node EXCLUSIVE = null;

        //waitStatus的一常量值,表示线程已取消
        static final int CANCELLED =  1;
        //waitStatus的一常量值,表示后继线程需要取消挂起
        static final int SIGNAL    = -1;
        //waitStatus的一常量值,表示线程正在等待条件
        static final int CONDITION = -2;
        //waitStatus的一常量值,表示下一个acquireShared应无条件传播
        static final int PROPAGATE = -3;

        //waitStatus,其值只能为CANCELLED、SIGNAL、CONDITION、PROPAGATE或0
        //初始值为0
        volatile int waitStatus;

        //前驱节点
        volatile Node prev;

        //后继节点
        volatile Node next;

        //当前节点的线程,在节点初始化时赋值,使用后为null
        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;
        }
    }

上边的Node正是等待队列里的二个节点,具体组织如下:
澳门网上唯一授权赌城 1

紧接着,来看一下AbstractQueuedSynchronizer的多少个举足轻重性质:

    //等待队列的头结点
    private transient volatile Node head;
    //等待队列的尾节点
    private transient volatile Node tail;
    //同步状态,这个很重要
    private volatile int state;

从那就足以赢得同步队列的主干组织:
澳门网上唯一授权赌城 2

再者,同步器中提供了三个章程用于操作同步状态:

    protected final int getState() {
        return state;
    }

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

    //使用CAS设置同步状态,确保线程安全
    protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

AbstractQueuedSynchronizer类中任何格局首借使用于插入节点、释放节点,插入节点进度如下图所示:
澳门网上唯一授权赌城 3

放活头结点过程如下图所示:
澳门网上唯一授权赌城 4

依附队列的野趣是,我们用锁来验证,举例多个线程想要得到同贰个指标上的锁,那么这个线程会依据申请锁的前后相继顺序在该锁对象中的八个FIFO队列上排队等候(也正是将那几个线程对象的援引插入到该锁的行列中卡塔尔国。AQS是Java并发的根底框架,同一时候AOS的落实的根底却是 sun.misc.Unsafe 和 volatile,当然还只怕有LockSupport工具类,LockSupport也是依附Unsafe,首要达成线程的“窒碍”(park卡塔尔和线程的“唤醒窒碍”(unpark卡塔尔。基本原理是 sun.misc.Unsafe 保障了内部存款和储蓄器操作的“原子性”,而volatile保险了内存“可以见到性”。Unsafe的源码能够参见: ,它提供了各样原子性的内存CAS操作。

AQS完成分析

AQS的里边通过Node内部类贰个个连接起来完成FIFO同步队列。Node类的结构如下所示:

澳门网上唯一授权赌城 5

AQS的静态内部类Node

waitStatus代表Node之处,它的取值定义在Node中。此外AQS是分享照旧独自占领地获取同步状态,在Node内中也定义了对应的符号属性。

static final  class Node {
    /** 共享模式 */
    static final AbstractQueuedSynchronizer.Node SHARED = new AbstractQueuedSynchronizer.Node();
    /** 独占模式 */
    static final AbstractQueuedSynchronizer.Node EXCLUSIVE = null;

    /** 表示线程已被取消(等待超时或者被中断) */
    static final int CANCELLED =  1;
    /** 表示后继节点中的线程需要被唤醒(unpaking) */
    static final int SIGNAL    = -1;
    /** 表示结点线程等待在condition上(等待队列),当被signal后,会从等待队列转移到同步到队列中 */
    static final int CONDITION = -2;
    /** 表示下一次共享模式下同步状态会被无条件地传播下去 */
    static final int PROPAGATE = -3;
    /** 除了上面定义的4中状态之外,waitStatus在初始化还能取值为0,即表示初始状态 */
}

浅析总括

AbstractQueuedSynchronizer落成了对资源获得与释放的功底达成,真正使用到的地点还在是各样具体的机能类中,如CountDownLatch、ReentrantLock等,前边在此些类中会具体解析。

本文从ReentrantLock的达成来发轫探寻AbstractQueuedSynchronizer。为了好把握大势,大家将ReentrantLock的源码(Java1.8.0_40卡塔尔简化如下:

垄断(monopoly卡塔尔(英语:State of Qatar)形式获得同步状态

攻克情势下获得同步状态的点子有:tryAcquireNanos(int arg, long nanosTimeout卡塔尔国、acquireInterruptibly(int arg卡塔尔(قطر‎、acquire(int arg卡塔尔(قطر‎。
tryAcquireNanos既可以协理线程响应中断(即在协同队列中,借使线程被中止,则方法会抛出InterruptedException十分),又能扶持过期;acquireInterruptibly方法只辅助响应中断;acquire中断和过期都不扶植。上面看看acquire(int arg卡塔尔国内部贯彻

public final void acquire(int arg) {
    /**
     * tryAcquire:获取同步状态,同步组件中的子类中自己重写实现
     * addWaiter:将当前线程放入Node节点中,再将Node节点放入同步队列中
     * acquireQueued:在同步队列中自旋获取同步状态,这个方法会使节点中的线程阻塞等待
     */
    if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), arg))
        selfInterrupt();
}

acquire方法中做了如下几件事

  • 尝试得到同步状态,假诺成功直接回到,退步则三番若干回;
  • 布局Node节点,将近来线程归入个中;
  • 将协会好的Node节点放入由Node组成的一块儿队列;
  • Node中的线程在合作队列中自旋等待。

tryAcquire(int arg卡塔尔(قطر‎方法的效果与利益正是让一齐组件本身完结的,所以达成得看具体组件。上面看看addWaiter方法是怎么样兑现的

澳门网上唯一授权赌城 6

CAS设置尾节点

private AbstractQueuedSynchronizer.Node addWaiter(AbstractQueuedSynchronizer.Node mode) {
    //使用当前线程构造node节点
    AbstractQueuedSynchronizer.Node node = new AbstractQueuedSynchronizer.Node(
            Thread.currentThread(), mode);
    AbstractQueuedSynchronizer.Node pred = tail;
    //队列不为空
    if (pred != null) {
        node.prev = pred;
        /* 通过cas将当前节点放入同步队列的尾部,因为多线程环境下获取锁成功的线程只有一个,
         * 所以会有多个线程需要放入同步队列尾部,因此此处需要通过cas保证线程安全。
         * 同时compareAndSetTail可能失败,所以下面得调用enq(node)方法,执行重复的代码
         */
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

private AbstractQueuedSynchronizer.Node enq(final AbstractQueuedSynchronizer.Node node) {
    for (;;) {  //通过死循环和compareAndSetTail方法保证当前线程一定能放入队尾
        AbstractQueuedSynchronizer.Node t = tail;
        if (t == null) { 
            if (compareAndSetHead(new AbstractQueuedSynchronizer.Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

enq内部是个死循环,通过CAS设置尾结点,不成功就直接重试,很精髓的CAS自旋的用法。

acquireQueued方法会使得同步队列中的各样节点自旋获取同步状态,具体贯彻如下

final boolean acquireQueued(final AbstractQueuedSynchronizer.Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        // 自旋等待
        for (;;) {
            //找到当前结点的前驱结点
            final AbstractQueuedSynchronizer.Node p = node.predecessor();
            // 只有前驱节点是head,才尝试获取同步状态
            if (p == head && tryAcquire(arg)) {
                //获取同步状态成功,将当前结点设置为头结点。
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            /**
             * shouldParkAfterFailedAcquire: 判断是否应该阻塞当前线程
             * parkAndCheckInterrupt:真正让线程阻塞等待
             * 阻塞之前先判断是否能阻塞
             */
            if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

acquireQueued内部自旋,决断当前节点是还是不是为老二节点(head是特别节点),当前节点是老二节点就去尝尝获得同步状态,假若获得成功则赶回,不然的话拥塞当前线程。
线程拥塞通过LockSupport.park(this卡塔尔;来促成。不过在调用堵塞在此之前会先通过shouldParkAfterFailedAcquire方法通过waitStatus的值来推断是不是供给调用堵塞。

private static boolean shouldParkAfterFailedAcquire(AbstractQueuedSynchronizer.Node pred, AbstractQueuedSynchronizer.Node node) {
    //获取前驱节点的waitStatus值
    int ws = pred.waitStatus;
    //若前驱结点的状态是SIGNAL,意味着当前结点可以被安全地唤醒(park)
    if (ws == AbstractQueuedSynchronizer.Node.SIGNAL)
        return true;
    if (ws > 0) {
        /* ws>0,只有CANCEL状态ws才大于0。若前驱结点处于CANCEL状态,也就是此结点线程
         * 已经无效,从后往前遍历,找到一个非CANCEL状态的结点,将自己设置为它的后继结点
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        // 若前驱结点为其他状态,将其设置为SIGNAL状态
        compareAndSetWaitStatus(pred, ws, AbstractQueuedSynchronizer.Node.SIGNAL);
    }
    return false;
}

能够看来独有前驱节点的waitStatus是SIGNAL,当前才须求调用梗塞。
大器晚成体独占情势下拿到同步状态的流程图如下

澳门网上唯一授权赌城 7

acquire方法施行流程

面试考试的场合

AQS是何等?内部落实协会理解吗?
AbstractQueuedSynchronizer简单的称呼AQS,它为促成依据于先进先出 (FIFO卡塔尔(قطر‎等待队列的封堵锁和连锁同步器(数字信号量等)提供一个底子完结框架。内部落到实处布局参照他事他说加以考察上边的图示作答。
澳门网上唯一授权赌城 8

public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        abstract void lock();

        final boolean nonfairTryAcquire(int acquires) {
            // ... ...
        }

        protected final boolean tryRelease(int releases) {
           // ... ...
        }
        // ... ...
    }

    /**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
           // ... ...
        }
    }

    public ReentrantLock() {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    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 void unlock() {
        sync.release(1);
    }
    public Condition newCondition() {
        return sync.newCondition();
    }
    // ... ...
}

占有方式释放同步状态

线程实践完自个儿的逻辑之后,会自由同步状态。独自据有方式下放出同步状态的法子如下

public final boolean release(int arg) {
    //尝试释放同步状态,成功的话唤醒后继节点,该方法使用者要重写
    if (tryRelease(arg)) {
        AbstractQueuedSynchronizer.Node h = head;
        if (h != null && h.waitStatus != 0)
            //唤醒后继节点
            unparkSuccessor(h);
        return true;
    }
    return false;
}

unparkSuccessor的贯彻如下

private void unparkSuccessor(AbstractQueuedSynchronizer.Node node) {
    // 获取waitStatus,并将其设置为0
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    // 获取头节点的后继节点
    AbstractQueuedSynchronizer.Node s = node.next;
    if (s == null || s.waitStatus > 0) { // waitStatus>0表示取消状态
        s = null;
        //从队尾往前遍历找到一个处于正常阻塞状态的结点进行唤醒
        for (AbstractQueuedSynchronizer.Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        // 相当于通知(notify),将后继节点唤醒
        LockSupport.unpark(s.thread);
}

释放同步状态时,会将头节点的后继节点唤醒。

能够显著的看来,ReentrantLock 达成的所以接口都是依靠他的实例属性——同步器sync来兑现的,从结构函数能够看出,ReentrantLock暗中同意是非公平锁——使用非公平同步器NonfairSync,传入true时获得的是比量齐观锁——使用公平同步器FairSync。而那二者都以继续于肤浅类Sync,而空虚类Sync又三回九转于我们的AbstractQueuedSynchronizer。大家先全体看下AQS的实今世码:

分享方式获得同步状态

共享式同步组件来说,同不日常刻可以有四个线程同期获取到协同状态。

public final void acquireShared(int arg) {
    // tryAcquireShared尝试获取同步状态,使用者需要重写实现
    if (tryAcquireShared(arg) < 0)
        //代码执行到这里,表示同步状态获取失败,需要排队
        doAcquireShared(arg);
}

private void doAcquireShared(int arg) {
    // 构建共享节点,放入同步队列中
    final AbstractQueuedSynchronizer.Node node = addWaiter(AbstractQueuedSynchronizer.Node.SHARED);
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            // 前驱节点
            final AbstractQueuedSynchronizer.Node p = node.predecessor();
            //只有前驱是头结点,才有机会尝试获取同步状态
            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) &&
                    parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

能够看见,分享方式下的一头状态获得基本和操纵格局相通。

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
    static final class Node {   
        volatile int waitStatus;
        volatile Node prev;
        volatile Node next;
        volatile Thread thread;
        Node nextWaiter;
        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;
        }
    }
    /**
     * Head of the wait queue, lazily initialized. 
     */
    private transient volatile Node head;
    /**
     * Tail of the wait queue, lazily initialized.  
     */
    private transient volatile Node tail;
    /**
     * The synchronization state.
     */
    private volatile int state;
    /**
     * Inserts node into queue, initializing if necessary. See picture above.
     * @param node the node to insert
     * @return node's predecessor
     */
    private Node enq(final Node node) {
       // ... ...
    }

    /**
     * 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) {
        // ... ...
    }

    /**
     * Sets head of queue to be node, thus dequeuing. Called only by
     * acquire methods.  Also nulls out unused fields for sake of GC
     * and to suppress unnecessary signals and traversals.
     * @param node the node
     */
    private void setHead(Node node) {
        // ... ...
    }

    public class ConditionObject implements Condition, java.io.Serializable {
        private static final long serialVersionUID = 1173984872572414699L;
        /** First node of condition queue. */
        private transient Node firstWaiter;
        /** Last node of condition queue. */
        private transient Node lastWaiter;
        // ... ...
    }
}

分享形式释放同步状态

分享格局下,由于有四个线程持有同步状态,所以释放的时候须要保险线程安全。

private void doReleaseShared() {
    //死循环,持有同步状态的线程可能有多个,采用循环CAS保证线程安全
    for (;;) {
        AbstractQueuedSynchronizer.Node h = head;
        if (h != null && h != tail) {
            int ws = h.waitStatus;
            // 当头节点的ws为SIGNAL才唤醒后继节点
            if (ws == AbstractQueuedSynchronizer.Node.SIGNAL) {
                // 将头节点的waitStatus置为0
                if (!compareAndSetWaitStatus(h, AbstractQueuedSynchronizer.Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                // 唤醒后继节点
                unparkSuccessor(h);
            }
            else if (ws == 0 &&
                    !compareAndSetWaitStatus(h, 0, AbstractQueuedSynchronizer.Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        if (h == head)                   // loop if head changed
            break;
    }
}

AbstractQueuedSynchronizer的兑现满含了多个里面类,Node 类和 ConditionObject类,而后人只有在利用 ReentrantLock.newCondition(卡塔尔(英语:State of Qatar)时才会用到,这几天不去管它。Node类首要用作FIFO队列上的节点,存储在锁上等待的具备线程对象的消息。提供了enq(final Node node卡塔尔(قطر‎方法用于插入队列尾巴部分,addWaiter(Node mode卡塔尔(英语:State of Qatar)方法用于到场FIFO队列,setHead(Node node卡塔尔用于初叶化FIFO队列的头部。所以AbstractQueuedSynchronizer未有大家想象的那么复杂,它根本是用以落实三个FIFO的守候队列(我们有时放下ConditionObject不管卡塔尔国,以至处理同步器的情况status。

由此AQS完成叁个自定义锁

澳门网上唯一授权赌城,在咱们的自定义锁中,维护多个AQS子类的个中类,该AQS子类重写tryAcquire(int acquire卡塔尔(英语:State of Qatar)和tryRelease(int releases卡塔尔国方法。然后加锁调用AQS的模板方法acquire(int arg卡塔尔(قطر‎,释放锁调用AQS的沙盘模拟经营方法release(int arg卡塔尔(英语:State of Qatar)就可以。具体落实如下

public class Mutex implements Lock,Serializable {

    // 定义AQS的子类,主要依靠这个子类来实现定义锁
    private static class Sync extends AbstractQueuedSynchronizer {
      // 锁是否被占用
      protected boolean isHeldExclusively() { 
        return getState() == 1; 
      }

      // state=0时,获取锁,state+1
      public boolean tryAcquire(int acquires) {
        assert acquires == 1; // Otherwise unused
       if (compareAndSetState(0, 1)) {
         setExclusiveOwnerThread(Thread.currentThread());
         return true;
       }
       return false;
      }

      // 释放锁,让state置为0
      protected boolean tryRelease(int releases) {
        assert releases == 1; // Otherwise unused
        if (getState() == 0) throw new IllegalMonitorStateException();
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
      }

      // Provide a Condition
      Condition newCondition() { return new ConditionObject(); }

      // Deserialize properly
      private void readObject(ObjectInputStream s) 
        throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
      }
    }

    // The sync object does all the hard work. We just forward to it.
    private final Sync sync = new Sync();

    public void lock()                { sync.acquire(1); }
    public boolean tryLock()          { return sync.tryAcquire(1); }
    public void unlock()              { sync.release(1); }
    public Condition newCondition()   { return sync.newCondition(); }
    public boolean isLocked()         { return sync.isHeldExclusively(); }
    public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
    public void lockInterruptibly() throws InterruptedException { 
      sync.acquireInterruptibly(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit) 
        throws InterruptedException {
      return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
 }

参考
《Java并发编程的章程》

我们在看一下他世袭的父类:

public abstract class AbstractOwnableSynchronizer implements java.io.Serializable {
    protected AbstractOwnableSynchronizer() { }
    /**
     * The current owner of exclusive mode synchronization.
     */
    private transient Thread exclusiveOwnerThread;

    protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }

    protected final Thread getExclusiveOwnerThread() {
        return exclusiveOwnerThread;
    }
}

很简短,正是落到实处了互斥同步器的持有者的成效,举个例子互斥锁正被哪些线程据有者。

我们大致驾驭了AbstractQueuedSynchronizer之后,大家再从细节上细致解析ReentrantLock的落到实处。

1)ReentrantLock.lock完结解析澳门网上网址平台,:

ReentrantLock分为公平和非公平的锁,NonfairSync 和 FairSync的lock实现各自如下:

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

 

NonfairSync.lock 和 FairSync.lock完结差别唯有两行代码:

if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());

便是这两行代码使得了 NonfairSync.lock 的锁的完结是非公平的,这两行代码的情趣是:假如sync同步器的情景为0,也等于锁未有被占,那么就安装为1,也正是那时候赢得锁,并且安装锁的具备者。也便是说非公平锁,能够不进去等待队列而直接获得锁,而且不管是还是不是在她的前段时间已经有其余线程在守候着收获该锁,那正是“不公正”锁的案由之豆蔻梢头。原因之二是它们的调用 acquire(1卡塔尔; 都以在 AQS 中,都各自调用了子类中的tryAcquire,而NonfairSync.tryAcquire 和 FairSync.tryAcquire实现又分裂:

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

本文由澳门网络娱乐游戏平台发布于编程,转载请注明出处:【澳门网上网址平台】Java并发功底框架AbstractQueuedSynchronizer初探(ReentrantLock的兑现剖判卡塔尔

相关阅读