对于RreentrantLock源码的一些理解

该文只是作为个人对于占小狼关于深入浅出java同步器AQS文的自己一些补充,建议先看他的文章之后再来看该文。有理解不对的地方望提出来共同学习。

AQS实现原理是通过子类重写tryAcquire和tryRelease方法通过CAS指令修改状态变量state。(接下来我们会将AbstractQueuedSynchronizer简写成AQS方便书写)

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

而我这里想解释下RreentrantLock内部对于tryAcquire()以及tryRelease()的一些自己理解。
对于RreentrantLock主要内部是通过构造的时候,判断内部使用公平锁还是非公平锁从而导致使用的时候有一些差异。

public ReentrantLock() {
        sync = new NonfairSync();
 }
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
 }

这里公平锁FairSync和NonfairSync都是继承自Sync,我们先看下Sync。

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.
         */
        //lock是由我们的子类来实现
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        //他默认实现了非公平锁的Acquire, 通过isLocked方法我们可以知道,state为0的时候为未上锁状态,而非0则为上锁状态
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //如果没有上锁,直接通过CAS修改state,如果修改成功,则说明请求锁成功,将exclusiveOwnerThread设置为当前线程,这个属性实际是AQS父类AbstractOwnableSynchronizer内的属性,实际就是为了记录当前线程
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //这里如果已经上锁了,则判断当前上锁的线程是否为当前线程,是的话继续操作,否则直接返回false
            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
        }
    }

接下来看下非公平锁:

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

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        //非公平锁会直接去设置state,如果当前state=0则直接相当于获得锁,否则就调用了AQS的acquire(1)
        //我理解非公平锁不公平的原因在于比如现在AQS的等待队列有两个在等待获得锁的线程,当前获得锁的线程释放了锁,而这时候我们使用NonfairSync调用lock
        //的时候,不需要看等待队列是否有等待获得锁的线程,而是直接和等待队列的下一个获得锁的线程竞争锁,如果竞争成功了,从而直接获得了该锁,导致
        //等待队列中应该获得锁的线程继续等待,从而导致了不公平性。
        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;

        //根据上面的分析,这里直接调用AQS的acquire,如果没有获得锁则直接加入到AQS的等待锁的线程队列,从而下次有锁释放直接从队列第一位获得锁,保证了公平性
        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;
        }
    }

AQS的hasQueuedPredecessors:

public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        //尾节点
        Node t = tail; // Read fields in reverse initialization order
        //头节点
        Node h = head;
        Node s;
        //如果尾节点==头节点的时候,这个时候我们认为等待队列没有在等待的线程
        //如果头节点!=尾节点但是头节点head.next == null,那么这种情况可能是这个时候正好被锁的线程释放锁,并且等待队列只有一个等待,直接变为了head从而head.next变为空,所以说明肯定是有前一个要获得锁或者等待锁的节点
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

你可能感兴趣的:(对于RreentrantLock源码的一些理解)