ReentrantLock


  • ReentrantLock重入实现Lock接口的一个
  • 支持重入性(表示能够对共享源能,即当前线该锁再次取不会被阻synchronized式支持重入性
  • ReentrantLock支持公平和非公平锁两种方式。

 

ueapoq  (ιμηαι.ιηι :Ιμη ιηομΚΚΙ.  ?Α?  ΔΙΟΙ

 

 

ReentrantLock是J.U.C包下提供的独占锁锁,根其名称可知,该锁是可重入的。

如果线程重入了一个,那ReentrantLock的锁计数器会加1,个解锁请求,锁计数器1。当锁计数器0的候,表示源被解了。

 

synchronized通操作Mark Word实现锁标识于Mark Word中,取和放都是式的,实现的原理是通过编译后加上不同的机器指令来实现;ReentrantLock通AQS(抽象同步队列)实现锁标识于AQS的state属性中。

 

ReentrantLock在上锁时,会根例化指定的策略去认为非公平。如果上成功,态值+1(重入,最大次数 Integer.MAX_VALUE),并将持有者当前线例。在 Sync 内部维护了一个列,存放了所有上线程。公平在上前,会检查在自己前面是否有其他线程等待,如果有就放弃竞争,继续等待。而非公平个机会,不管是否前面是否有其线程等待,

 

ReetrantLock在锁时,将状态计数器一(重入),当状态计数器0可用。此等待列中寻找线醒,始,如果列正在更新中,且未到合线程,那寻找

 

ReentrantLock实现又可以分为两类,分是公平和非公平,分由ReentrantLock中的个内部FairSync和NonfairSync来实现。FiarSync和NonfairSync均承了Sync,而Sync承了AbstractQueuedSynchronizer(AQS),所以ReentrantLock最是依AQS来实现锁的。

 

重要方法

 

public class ReentrantLock implements Lock, java.io.Serializable {}

 

// 方法,取不到线程会到同步队列中阻

void lock();

// 取可中断的

void lockInterruptibly() throws InterruptedException;

// 尝试获,如果,立返回 true,否返回 false

boolean tryLock();

// 有超等待时间,如果超时时间到了,然没有,返回 false

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

//

void unlock();

// 得到新的 Condition

Condition newCondition();

 

// 同器 Sync 的个子类锁

static final class FairSync extends Sync {}

static final class NonfairSync extends Sync {}

abstract static class Sync extends AbstractQueuedSynchronizer {}

 

 

造器

 

ReentrantLock 造器有两种

 

//参数造器,相当于 ReentrantLock(false),是非公平的

public ReentrantLock() {

    sync = new NonfairSync();

}

 

public ReentrantLock(boolean fair) {

    sync = fair ? new FairSync() : new NonfairSync();

}

 

公平

FairSync 公平实现了 lock 和 tryAcquire 个方法,lock 方法非常简单,如下:

 

// acquire 是 AQS 的方法,表示先尝试获,失之后入同步队列阻等待

 

final void lock() {

    acquire(1);

}

 

在 FairSync 并没有重写 acquire 方法代用的 AbstractQueuedSynchronizer 的代,如下:

 

public final void acquire(int arg) {

    if (!tryAcquire(arg) &&

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

        selfInterrupt();

}

 

lock  lock  FairSync.lock  NonfairSync.l  ock  AQS.acquire  AQS.acquire  FairSync.  tryAcquire  Sync.  NonfairSync.  nonfairTryAc  tryAcquire  quire

 

 

使用

 

Lock lock = new ReentrantLock();

lock.lock();

try {

  doSomething();

}finally {

  lock.unlock();

}

 

锁实现

 

AbstractQueuedSynchronizer的实现类取和放都是基于Sync,AbstractQueuedSynchronizer不清楚的,可以看下

abstract static class Sync extends AbstractQueuedSynchronizer {

 

        //抽象方法,由NonfairSync和FairSync实现,公平的是非公平的

        abstract void lock();

 

        //在NonfairSync中使用到,非公平的

        //@param acquires 要取的

        final boolean nonfairTryAcquire(int acquires) {

            //取当前要加线

            final Thread current = Thread.currentThread();

            //的状,即AQS的属性state

            int c = getState();

            //如果的状等于0,表示

            if (c == 0) {

                //使用CAS更新,将更新成要取的

                if (compareAndSetState(0, acquires)) {

                    //如果CAS更新成功,表示成功,将当前线占有线程,即置属性exclusiveOwnerThread当前线

setExclusiveOwnerThread(current);

                    //返回加成功

                    return true;

                }

            }

            //当前已被占有,判断占有线程是否是当前线程,如果不是直接返回

            else if (current == getExclusiveOwnerThread()) {

                //的原有状加上来要取的数得到新的态值

                int nextc = c + acquires;

                //如果算出的状态值数,直接出Error错误,但是感觉这里会有问题,比如原来的态值为1,入-1也会把锁给释这样操作就成了操作

                if (nextc < 0) // overflow

                    throw new Error("Maximum lock count exceeded");

                //的状态值为新的状态值nextc

                setState(nextc);

                //返回成功

                return true;

            }

            //返回

            return false;

        }

 

        //此方法在ReentrantLock的unLock方法中使用到,,修改的状         

        //此方法能在占有线用,即unLock方法能在持有线

        //@param releases 要放的

        protected final boolean tryRelease(int releases) {

            //得到的新状态值

            int c = getState() - releases;

            //如果当前线程不是持有线程,直接出IllegalMonitorStateException

            if (Thread.currentThread() != getExclusiveOwnerThread())

                throw new IllegalMonitorStateException();

            //是否成功的志位

            boolean free = false;

            //如果新的态值为0

            if (c == 0) {

                //将是否成功的志位成功

                free = true;

                //将占有独占线程,即属性exclusiveOwnerThread置

setExclusiveOwnerThread(null);

            }

            //的状

            setState(c);

            //返回成功

            return free;

        }

 

        //判断当前线程是否是持有线程,如果是返回true,否返回false         

        protected final boolean isHeldExclusively() {

            //返回当前线程是否是持有线

            return getExclusiveOwnerThread() == Thread.currentThread();

        }

 

        //建条件例ConditionObject

        final ConditionObject newCondition() {

            //返回新建的ConditionObject

            return new ConditionObject();

        }

 

        //取占有线

        final Thread getOwner() {

            //如果当前,返回null,否返回占有线

            return getState() == 0 ? null : getExclusiveOwnerThread();

        }

 

        //得到的被取数,也是的状能在持有线程操作才能取到的状,即的被取数,否直接返回0

        final int getHoldCount() {

            //能在持有线程操作才能取到的状,即的被取数,否直接返回0

            return isHeldExclusively() ? getState() : 0;

        }

 

        //判断是否有被线程占有,即的状是否是于加的状

        final boolean isLocked() {

            //的状不等于0,表明线程占有,态处于加

            return getState() != 0;

        }

 

        //工作流中得到象,此方法目前没有使用到

        private void readObject(java.io.ObjectInputStream s)

            throws java.io.IOException, ClassNotFoundException {

            s.defaultReadObject();

            //重新的状

            setState(0); // reset to unlocked state

        }

}

 

NonfairSync

 

static final class NonfairSync extends Sync {

        private static final long serialVersionUID = 7316153563782823691L;

 

        //Sync的抽象lock方法的重写,非公平的,在Reentrantlock的lock方法使用到

        final void lock() {

            //使用CAS将的状0更新成1,即加操作

            if (compareAndSetState(0, 1))

                //如果加成功,将当前线占有线程,即置属性exclusiveOwnerThread当前线

setExclusiveOwnerThread(Thread.currentThread());

            else

                //NonfairSyncAQS中承下来的方法,下面在讲锁详细的介

                acquire(1);

        }

 

//NonfairSync重写了AbstractQueuedSynchronizer的tryAcquire模板方法,否AQS中的tryAcquire方法会直接  UnsupportedOperationException

        //tryAcquire方法在acquire中使用到,非公平的都是基于此方法

        //@param acquires 要取的

        protected final boolean tryAcquire(int acquires) {

            //nonfairTryAcquire方法,在上面Sync内部中有行介,非公平的需判断同步队列中前面是否有点也在

            return nonfairTryAcquire(acquires);

        }

}

 

FairSync

 

static final class FairSync extends Sync {

        //Sync的抽象lock方法的重写,公平的,在Reentrantlock的lock方法使用到

//FairSync的lock方法和NonfairSync的lock方法的区是,NonfairSync的lock方法会尝试,如果锁获取不到才会用acquire方法,acquire内部也会尝试,如果取不到加入到同步队列中循环获

        final void lock() {

            //FairSync AQS中承下来的方法,下面在讲锁详细的介

            acquire(1);

        }

 

//NonfairSync重写了AbstractQueuedSynchronizer的tryAcquire模板方法,否AQS中的tryAcquire方法会直接出UnsupportedOperationException

        //tryAcquire方法在acquire中使用到,公平的取都是基于此方法

//tryAcquire方法和NonfairSync的tryAcquire方法不同的是需要用hasQueuedPredecessors方法,判断头节点的下一个点的线程是否是当前线程,如果不是表明前面有等待线

        //@param acquires 要取的

        protected final boolean tryAcquire(int acquires) {

            //取当前要加线

            final Thread current = Thread.currentThread();

            //的状,即AQS的属性state

            int c = getState();

            //如果的状等于0,表示

            if (c == 0) {

                //AQS承下来的hasQueuedPredecessors方法判断同步队列是否有点的线程,如果是就不行直接

                if (!hasQueuedPredecessors() &&

                    //如果AQS同步队列中没有等待要点的线程,使用CAS更新的状

                    compareAndSetState(0, acquires)) {

setExclusiveOwnerThread(current);

                    //返回公平的成功

                    return true;

                }

            }

            //如果当前线程是占有线

            else if (current == getExclusiveOwnerThread()) {

                //的原有状加上来要取的数得到新的态值

                int nextc = c + acquires;

                //如果算出的状态值数,直接出Error错误

                if (nextc < 0)

                    throw new Error("Maximum lock count exceeded");

                //的状态值为新的状态值nextc

                setState(nextc);

                //返回公平的成功

                return true;

            }

            //返回公平的

            return false;

        }

}

 

独占模式加机制

 

lock

 

锁时首先使用CAS算法尝试将state状态变1,置成功后,表示当前线取到了,然后将独占有者当前线程;

如果CAS置不成功,则进入Acquire方法行后续处理。

 

final void lock() {

    // 使用CAS算法尝试将state状态变1

    if (compareAndSetState(0, 1))

        // 置成功后,表示当前线取到了,然后将独占有者当前线

setExclusiveOwnerThread(Thread.currentThread());

    else

        // 行后续处理,会及到重入性、建Node点加入到列尾等

        acquire(1);

}

 

Acquire

 

acquire(1) 方法是AQS提供的方法

 

public final void acquire(int arg) {

    /**

     * 使用tryAcquire()方法,当前线尝试获取同步锁取成的,就不会行后面的acquireQueued()

     * 方法了,是由于 && 逻辑运算符的特性决定的。

     *

     * 如果使用tryAcquire()方法取同步锁,就会继续执行acquireQueued()方法,的作用是

     * 一直死循步队列,直到使addWaiter()方法建的点中线取到

     *

     * 如果acquireQueued()返回的true,个true不是代表成功的取到,而是代表当前线程是否存在

     * 中断志,如果存在的,在取到同步锁后,需要使用selfInterrupt()当前线行中断。

     */

    if (!tryAcquire(arg) &&

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

        selfInterrupt();

}

 

tryAcquire

//NonfairSync 非公平中重写了AQS的tryAcquire()方法

final boolean nonfairTryAcquire(int acquires) {

    // 当前线

    final Thread current = Thread.currentThread();

    // 取当前state同态变,由于使用volatile修独的写操作具有原子性

    int c = getState();

    // 如果状态值为0

    if (c == 0) {

        // 使用compareAndSetState方法个CAS算法尝试将state同态变1 取同步锁

        if (compareAndSetState(0, acquires)) {

            // 然后将独占有者当前线

            setExclusiveOwnerThread(current);

            return true;

        }

    }

    // 如果有独占的的线程是当前线程的,表示当前线程需要重复获(重入

    else if (current == getExclusiveOwnerThread()) {

        // 当前同state加1

        int nextc = c + acquires;

        if (nextc < 0) // overflow

            throw new Error("Maximum lock count exceeded");

        // 写入state同态变,由于使用volatile修独的写操作具有原子性

        setState(nextc);

        return true;

    }

    return false;

}

 

protected final boolean tryAcquire(int acquires) {

    final Thread current = Thread.currentThread();

    int c = getState();

    if (c == 0) {

        /**

         * 通过对比源码发现,公平比非公平多了这块: !hasQueuedPredecessors()

         * hasQueuedPredecessors() 是么呢?就是判断当前同步队列中是否存在点,如果存在

         * 就返回true,由于前面有个 !,那就是false,再根 && 逻辑运算符的特性,不会继续执行了;

         *

         * tryAcquire()方法直接返回false,后面的逻辑就和非公平的一致了,就是建Node点,并将

         * 点加入到同步队列尾; 公平发现当前同步队列中存在点,有线程在自己前面已,那自己就得乖乖的向后面排去。

         *

         */

        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;

}

 

addWaiter

private Node addWaiter(Node mode) {

    // model参数是独占模式,认为null;

    Node node = new Node(Thread.currentThread(), mode);

    // 将当前同步队列的tail尾点的地引用赋值给pre

    Node pred = tail;

    // 如果pre不null,明同步队列中存在

    if (pred != null) {

        // 当前点的前驱结点指向pre尾

        node.prev = pred;

        // 使用CAS算法将当前点,使用CAS保其原子性

        if (compareAndSetTail(pred, node)) {

            // 尾置成功,将pre旧尾点的后继结点指向新尾点node

            pred.next = node;

            return node;

        }

    }

    // 如果尾null,表示同步队列中没有点,enq()方法将当前node入到列中

    enq(node);

    return node;

}

 

acquireQueued

final boolean acquireQueued(final Node node, int arg) {

    // 志cancelAcquire()方法是否

    boolean failed = true;

    try {

        // 志是否中断,认为false不中断

        boolean interrupted = false;

        for (;;) {

            // 取当前点的前驱结

            final Node p = node.predecessor();

            /**

             * 如果当前点的前驱结点已是同步队列的头结点了,明了点内容:

             * 1、其前驱结点已经获取到了同步锁了,并且锁还

             * 2、其前驱结点已经获取到了同步锁了,但是经释放了

             *

             * 然后使用tryAcquire()方法去尝试获取同步锁,如果前驱结点已经释放了,那就会取成功,

             * 否步锁获取失继续

             */

            if (p == head && tryAcquire(arg)) {

                // 将当前步队列的head头结

                setHead(node);

                // 然后将当前点的前驱结点的后继结点置null,垃圾

                p.next = null; // help GC

                failed = false;

                // 返回中断的

                return interrupted;

            }

            /**

             * shouldParkAfterFailedAcquire()是当前点的前驱结点的状态进行判断,以及去针对

             * 状出相应处理,由于文章问题,具体源本文不解;需知道如果前驱结点p的状态为

             * SIGNAL的,就返回true。

             *

             * parkAndCheckInterrupt()方法会使当前线去waiting状,并且看当前线程是否被中断,

             * interrupted() 同会将中断志清除。

             */

            if (shouldParkAfterFailedAcquire(p, node) &&

                parkAndCheckInterrupt())

                // 中断志置true

                interrupted = true;

        }

    } finally {

        if (failed)

            /**

             * 如果for(;;)循中出现异常,并且failed=false没有行的,cancelAcquire方法

             * 就会将当前线程的状 node.CANCELLED 已取消状,并且将当前点node移出

             * 同步队列。

             */

            cancelAcquire(node);

    }

}

 

独占模式

 

Unlock

public void unlock() {

    // 锁时,需要将state同态变值进 1,入参数 1

    sync.release(1);

}

release

public final boolean release(int arg) {

    // tryRelease方法:尝试释,成功true,失false

    if (tryRelease(arg)) {

        Node h = head;

        if (h != null && h.waitStatus != 0)

            // 头结点不空并且头结点的waitStatus不是初始化点情况,然后醒此阻线

            unparkSuccessor(h);

        return true;

    }

    return false;

}

 

tryRelease

protected final boolean tryRelease(int releases) {

    // 当前state状态值进

    int c = getState() - releases;

    // 如果当前独占有者不是当前线程,出 非法监视器状态 异

    if (Thread.currentThread() != getExclusiveOwnerThread())

        throw new IllegalMonitorStateException();

    boolean free = false;

    if (c == 0) {

        free = true;

        setExclusiveOwnerThread(null);

    }

    // 更新state同态值

    setState(c);

    return free;

}

 

unparkSuccessor

private void unparkSuccessor(Node node) {

    // 头结点waitStatus

    int ws = node.waitStatus;

    if (ws < 0)

        compareAndSetWaitStatus(node, ws, 0);

    // 取当前点的下一个

    Node s = node.next;

    // 如果下个点是null或者下个点被cancelled,就列最始的非cancelled状

    if (s == null || s.waitStatus > 0) {

        s = null;

        // 就尾部,到首,列第一个waitStatus<0的点。

        for (Node t = tail; t != null && t != node; t = t.prev)

            if (t.waitStatus <= 0)

                s = t;

    }

    // 如果当前点的后继结点不null,将其点中于阻线程unpark

    if (s != null)

        LockSupport.unpark(s.thread);

}