ReentrantLock源码

ReentrantLock与Synchronized区别在于后者是JVM实现,前者是JDK实现,属于Java对象,使用的时候必须有明确的加锁(Lock)和解锁(Release)方法,否则可能会造成死锁。

先来查看ReentrantLock的继承关系(下图),实现了Lock和Serializable接口,表明ReentrantLock对象是可序列化的。

同时在ReentrantLock内部还定义了三个重要的内部类,Sync继承自抽象类AbstractQueuedSynchronizer(队列同步器)。其后又分别定义了它的两个子类公平锁FairSync和非公平锁NonfairSync。

    /**
     * Base of synchronization control for this lock. Subclassed
     * into fair and nonfair versions below. Uses AQS state to
     * represent the number of holds on the lock.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        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;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    /**
     * Sync object for non-fair locks
     */
    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);
        }
    }

    /**
     * Sync object for fair locks
     */
    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;
        }
    }

然后先看一下ReentrantLock的构造函数:

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

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
ReentrantLock():无参构造器,默认的是非公平锁。
ReentrantLock(boolean):有参构造器,根据参数指定公平锁还是非公平锁。

从这里可以看出,ReentrantLock其实既可以是公平锁也可以是非公平锁,通过参数来进行创建。

然后我们看一下加锁方法Lock:

    public void lock() {
        sync.lock();
    }

内部是调用了构造器中创建的Sync对象,由于默认的是非公平锁,因此我们先来看一下非公平锁的实现。

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

从方法名compareAndSetState可以看出这是一个CAS操作,我们点进去查看源码,这是在AbstractQueuedSynchronized里面定义的一个方法

    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

通过Unsafe对象来进行CAS操作。由于Unsafe里面定义的是Native方法,通过其他语言实现了对内存的直接操作,因此是保证了线程安全的。

然后我们再来看操作成功后的代码:setExclusiveOwnerThread(Thread.currentThread());

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

这个方法的实现是在AbstractQueuedSynchronized的父类AbstractOwnableSynchronized中进行的,只是记录了当前拥有锁的线程。

然后我们再看看如果操作失败后的执行方法:acquire(1);

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

这个方法是被定义在AbstractQueuedSynchronized中,里面只有三行代码:

首先看最下面的如果条件成立执行的方法:selfInterrupt()

    static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

这个方法很简单,令当前线程中断。

然后我们再来看下上面的判断条件:

首先是tryAcquire(arg),调用非公平锁的tryAcquire(int),里面又调用了Sync的nonfairTryAcquire(int)方法,通过判断当前的锁状态是否等于0,等于则表示没有线程获取锁,尝试用CAS操作将其赋值为1,赋值成功记录当前获取锁的线程,赋值失败返回false。如果锁状态不等于0,则表示已经有线程获取到锁,此时会比较记录的线程是否为当前线程,如果是,则表示是当前线程重入(这里可以看出ReentrantLock是可重入锁),再令锁状态state加1,返回true,否则返回false。

在这里我们可以看到tryAcquire()目的是再次判断当前锁是否是可获取状态以及是否是同一个线程的重入操作。获取锁成功或者是线程重入则返回true,不再执行后面的线程中断。

    static final class NonfairSync extends Sync {

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

    abstract static class Sync extends AbstractQueuedSynchronizer {
        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;
        }
    }

再然后是addWaiter(Node);这里可以简单的理解当前线程没有获取到锁,因此被添加到等待队列中。

只不过这里的队列使用的是内部类Node定义的一个双向链表tail和head。注意的是tail和head都是volatile,同时也都是非静态变量,即每个对象的队列是互无关联的。

    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) { //判断当前尾节点是否等于null
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {  //尾节点不等于null,将当前节点添加在链表末尾作为尾节点。并对尾节点进行重新赋值。
                pred.next = node; 
                return node; //操作成功,返回当前节点。
            }
        }
        enq(node); //自旋获取锁
        return node;
    }

    private final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);  //这里是通过偏移量上值比较来进行值替换。
    }

    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;
                }
            }
        }
    }

新的线程被添加到链表里面后,再调用方法acquireQueue(Node,int);

这里可以简单的理解,通过自旋,如果当前节点是head节点的next,去尝试获取锁,获取到了则删除头节点,并返回false。获取不到则将线程节点的前一个节点的标志位设置为SIGNAL(表示下一个节点需要被unparking,即当前线程节点需要被unparking),然后令当前线程中断,停止循环。

    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;  //获取锁成功返回false;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt()) //不会一直循环下去,因为会不断地消耗资源,适时会进入中断,等待被唤醒后才继续自旋。
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

        final Node predecessor() throws NullPointerException { //获取当前节点的前节点
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus; //在这里Node的线程状态一共有5种情况:SIGNAL=-1,CANCELLED=1,CONDITION=-2,PROPAGATE=-3,以及默认值0
        if (ws == Node.SIGNAL)  //SIGNAL表示唤醒状态
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {  //大于0的只有CANCELLED情况,当前线程被取消执行,因此从队列中剔除
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {  //剩下的不论什么情况,都会利用CAS操作尝试将节点的waitStatus改为SINGAL,不论操作成功还是失败,都会返回false
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

    private static final boolean compareAndSetWaitStatus(Node node,
                                                         int expect,
                                                         int update) {  //利用CAS操作修改节点的waitStatus值
        return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                        expect, update);
    }

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

    private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        // Skip cancelled predecessors
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        // predNext is the apparent node to unsplice. CASes below will
        // fail if not, in which case, we lost race vs another cancel
        // or signal, so no further action is necessary.
        Node predNext = pred.next;

        // Can use unconditional write instead of CAS here.
        // After this atomic step, other Nodes can skip past us.
        // Before, we are free of interference from other threads.
        node.waitStatus = Node.CANCELLED;

        // If we are the tail, remove ourselves.
        if (node == tail && compareAndSetTail(node, pred)) {
            compareAndSetNext(pred, predNext, null);
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }

由此,整个非公平锁的加锁过程结束,总结一下:

1.如果state位是0,则表示没有线程获取对象锁,通过CAS操作设置state位从0到1,尝试获取锁

2.获取锁成功,记录当前获取锁的线程。流程结束

3.获取失败,判断是否是已经获取了锁的线程再次获取(通过第二步里面记录的线程与当前线程判断是否相等),如果是,令state再加1,流程结束

4.如果不是,将线程添加到链表队列中,然后进行自旋。

5.自旋时会判断当前线程是否是head节点的next,如果是则再次尝试获取锁,获取到了后将头节点替换为当前节点,返回false。流程结束

6.自旋一定次数后仍未获取到锁,或当前线程节点不是head节点的next,则进入中断。等待被唤醒后继续自旋。

公平锁的Lock()方法:

        final void lock() {
            acquire(1);
        }
        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;
        }
    }

公平锁与非公平锁的加锁方法区别在于,tryAcquire(int)方法的不同。公平锁中要判断队列里第一个线程是否是当前线程,如果是,则允许它获取锁,如果不是,则不能获取。

下面看一下解锁方法:unlock()

    public void unlock() {
        sync.release(1);
    }

内部不分公平锁与非公平锁,一律调用AbstractQueuedSynchronized方法的release(int)。

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

先看第一行的判断:if(tryRelease(arg))

里面先判断了锁指向的线程与当前线程相等,不相等则抛出异常。

再令status减1,判断结果是否等于0。等于0说明可以释放锁,将锁指向的线程改为null,status改为0,返回true。

不等于0则说明仍未全部执行完重入的操作,令status自减一,返回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;
        }

判断为false则释放锁失败,判断为true则继续执行if里面内容。

if里面主要是判断了链表队列head里面有等待唤醒的其他线程节点,对他们进行一个唤醒。

    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);  //将waitStatus赋值为初始状态0

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {  //下一个节点等于null或者被取消执行,从尾节点开始向前遍历,找到最头位置上的节点
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)  //唤醒队列中的下一个可执行的节点。
            LockSupport.unpark(s.thread);
    }

解锁流程总结:

1.锁指向的线程与当前线程必须是同一个线程。

2.锁标志位status必须已经减到0。

3.判断链表队列不等于null,并且头节点的waitStatus标志位不等于0,需要唤醒下一个节点。否则返回true,业务结束

4.唤醒下一个节点首先利用CAS操作将waitStatus的标志位改为0,然后再按队列顺序获取下一个节点。

5.如果获取的新节点等于null,或者waitStatus位等于1(表示已经被取消执行),则从尾节点向前遍历,直到遇见最前面的非null非当前线程节点的节点。

6.唤醒获取的新节点。业务结束

猜你喜欢

转载自www.cnblogs.com/yxth/p/10677528.html