preface

  • Reentrant mutex {@Link Lock} has the same basic behavior and semantics as implicit monitor locks accessed using {@code sync} methods and statements, but with extended functionality.

  • The thread that was last successfully locked but has not been unlocked has {@code ReentrantLock}.

  • When the lock does not belong to another thread, the thread that called {@code Lock} will return and successfully acquire the lock.

  • If the current thread already owns the lock, the method returns immediately.

  • This can be checked using the methods {@link #isHeldByCurrentThread} and {@link #getHoldCount}.

  • The constructor of this class accepts an optional fairness parameter.

  • When {@code true} is set, under contention the lock tends to grant access to the thread that has waited the longest.

  • Otherwise, this lock does not guarantee any particular access order.

  • A program that uses fair locking with many thread accesses may display lower overall throughput (that is, slower; Usually much slower), but the difference in time to get locked and guaranteed no hunger is smaller.

  • Note, however, that fairness of locks does not guarantee fairness of thread scheduling.

  • Thus, one of the multiple threads using a fair lock may acquire it multiple times in a row, while the other active threads are not engaged and do not currently hold the lock.

  • Also note that the untimed {@link #tryLock ()} method does not support fairness Settings.

  • If the lock is available, it will succeed even if other threads are waiting.

  • It is recommended to always call {@code lock} immediately with the {@code try} block, usually before/after construction, for example: class X { private final ReentrantLock lock = new ReentrantLock(); / /… public void m() { lock.lock(); // block until condition holds try { // … method body } finally { lock.unlock() }

  • In addition to implementing the {@link Lock} interface, this class defines a number of {@code public} and {@code protected} methods to check the status of the Lock.

  • Some of these methods are useful only for instrumentation and monitoring.

  • Serialization of this class behaves the same as a built-in lock: a deserialized lock is unlocked regardless of its state at serialization time.

  • Nm The lock supports up to 2147483647 recursive locks through the same thread.

  • Attempting to exceed this limit causes the locking method to raise {@link Error}.

The source code

package java.util.concurrent.locks;

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

    /**
     * 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() {
            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() {
            returngetState() ! = 0; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private voidreadObject(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);
        }

        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; }} /** * create {@code ReentrantLock} instance. This is equivalent to using {@code ReentrantLock (false)}. */ publicReentrantLock() { sync = new NonfairSync(); } /** * create an instance of {@code ReentrantLock} with the given fairness policy. * * @param fair {@codetrue} ifthis lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } /** * get the lock. * If no other thread holds the lock, the lock is acquired and returned immediately, setting the lock hold count to 1. * If the current thread already holds the lock, the hold count is increased by one and the method returns immediately. * If the lock is held by another thread, the current thread is disabled for thread scheduling purposes and sleeps until the lock is acquired, at which point the lock holding count is set to 1. */ public voidlock() { sync.lock(); } /** * The lock is obtained unless the current thread is {@linkplain Thread# interrupt interrupted}. * If no other thread holds the lock, the lock is acquired and returned immediately, setting the lock hold count to 1. * If the current thread already holds the lock, the hold count is increased by one, and the method returns immediately. * If the lock is held by another thread, the current thread is disabled for thread scheduling purposes and sleeps until one of two things happens: the lock is acquired by the current thread; Or some other thread {@linkplain Thread# interrupt Interrupts} the current thread. * If the current thread acquires a lock, the lock hold count is set to 1. * If the current thread: enters this method with a disconnection state set; {@linkplain Thread# interrupt interrupted} throws {@Link InterruptedException} and clears the interrupted status of the current thread. * In this implementation, because this method is an explicit breakpoint, it takes precedence over the response to the interrupt over normal or reentrant lock acquisition. */ public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } /** * The lock is acquired only if it is not held by another thread at the time of the call. * If no other thread holds the lock, the lock is acquired and the value {@code is immediately returnedtrue}, and set the lock hold count to 1. * Even if this lock is set to use a fair sorting strategy, a call to {@code tryLock ()} will immediately acquire the lock, regardless of whether other threads are currently waiting for it. * Even if it undermines fairness, this "bargaining" can be useful in some situations. * To comply with the fairness setting of this lock, use the nearly equivalent {@link#tryLock (long, TimeUnit) tryLock (0, timeunit.seconds)} (it will also detect interrupts).* If the current thread already holds the lock, the hold count is increased by one, and the method returns {@codetrue}. * This method returns the value {@code immediately if the lock is held by another threadfalse}。
     */
    public boolean tryLock() {
        returnsync.nonfairTryAcquire(1); } /** ** If the lock is not held by another thread within the given waiting time and the current thread is not {@linkplain Thread# interrupt interrupted}, the lock is acquired. * If no other thread holds the lock, the lock is acquired and the value {@code is immediately returnedtrue}, and set the lock hold count to 1. * If this lock is set to use a fair sorting strategy, the available lock will not be acquired if any other threads are waiting for the lock. * this with {@ the link#tryLock ()} instead.* If you want a timed {@code tryLock} that does allow insertion on a fair lock, combine timed and untimed forms together:if(lock.tryLock() || lock.tryLock(timeout, unit)) { ... }} * * If the current thread already holds the lock, the hold count is increased by one, and the method returns {@codetrue}. * If the lock is held by another thread, the current thread is disabled for thread scheduling purposes and sleeps until one of three things happens: the lock is acquired by the current thread; Or some other thread {@linkplain Thread# interrupt interrupts} the current thread; Or after a specified waiting time. * Return {@code if a lock is acquiredtrue}, and set the lock hold count to 1. * If the current thread: enters this method with a disconnection state set; {@linkplain Thread# interrupt interrupted} throws {@Link InterruptedException} and clears the interrupted status of the current thread. * Returns {@code if the specified wait time has elapsedfalse}. * If the time is less than or equal to zero, the method will not wait at all. * In this implementation, because this method is an explicit breakpoint, the response to the interrupt is prioritized over normal or reentrant lock acquisition, and the elapsed wait time is reported first. */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {returnsync.tryAcquireNanos(1, unit.toNanos(timeout)); } /** * Attempts to release the lock. * If the current thread is the holder of this lock, the retention count is reduced. * If the hold count is now zero, the lock is released. * if the current thread is not the holder of the lock, will cause {@ link IllegalMonitorStateException}. */ public voidunlock() { sync.release(1); } /** * returns the {@link Condition} instance used with this {@link Lock} instance. * Return {@link Condition} instances and {@link Object} monitor method ({@link Object #)wait(a)wait}, {@link Object# notify notify} and {@link Object# notifyAll when used with built-in monitor locking). * If this lock is not maintained when calling any {@link Condition} {@linkplain Condition# await () wait} or {@linkplain Condition# signal} methods, Will cause {@ link IllegalMonitorStateException}. * When the {@linkplain Condition# await () wait method} method is called, the lock is released and, before they return, the lock is reacquired and the lock hold count is restored to the state it was when the method was called. * If a thread is interrupted by {@linkplain Thread# interrupt interrupted} while waiting, the wait terminates, raising {@Link InterruptedException} and clearing the interrupted status of the thread. * Wait threads signal in FIFO order. * Threads returned from the wait method are reacquired in the same order as the thread that originally acquired the lock (not specified by default), but for fair locks, the thread with the longest wait is preferred. */ public ConditionnewCondition() {
        returnsync.newCondition(); } /** * Query the number of times the current thread holds the lock. * The thread owns a lock for each lock action that does not match the unlock action. * Reserved count information is usually only used for testing and debugging purposes. * For example, if an alreadyheld lock should not be used to enter a particular code segment, then we can assert the following fact: * * class X {* ReentrantLock lock = new ReentrantLock(); * / /... * public voidm() {
     *     assert lock.getHoldCount() == 0;
     *     lock.lock();
     *     try {
     *       // ... method body
     *     } finally {
     *       lock.unlock();
     *     }
     *   }
     * }}
     */
    public int getHoldCount() {
        returnsync.getHoldCount(); } /** * queries whether this lock is held by the current thread. * similar to the {@link Thread# holdsLock (Object)} method with built-in monitor locking, this method is usually used for debugging and testing. * For example, a method that should only be called if a lock is held could assert that this is the case: * class X {* ReentrantLock lock = new ReentrantLock(); * / /... * * public voidm() { * assert lock.isHeldByCurrentThread(); * / /... Method body *} *}} * it can also be used to ensure that a ReentrantLock is used in a non-reentrant way, for example: * class X {* ReentrantLock lock = new ReentrantLock(); * / /... * * public voidm() { * assert ! lock.isHeldByCurrentThread(); * lock.lock(); * try { * // ... method body * } finally { * lock.unlock(); * } * } * }} */ public booleanisHeldByCurrentThread() {
        returnsync.isHeldExclusively(); } /** * queries whether this lock is held by any thread. This method is designed for monitoring system state, not for synchronous control. */ public booleanisLocked() {
        return sync.isLocked();
    }

    /**
     * Returns {@code true} if this lock has fairness set true.
     *
     * @return {@code true} if this lock has fairness set true
     */
    public final boolean isFair() {
        returnsync instanceof FairSync; } /** * returns the thread that currently owns the lock; If not, return {@code null}. * When this method is called by a thread that is not the owner, the return value reflects the best approximation of the current locked state. * For example, the owner may temporarily {@code null} even if a thread tries to acquire the lock, but the owner does not yet own the owner. * This method is designed to facilitate the construction of subclasses that provide broader lock monitoring capabilities. */ protected ThreadgetOwner() {
        returnsync.getOwner(); } /** * queries if there are any threads waiting to acquire this lock. * Please note that since cancellation can happen at any time, {@codetrue} the return value does not guarantee that any other thread will acquire the lock. * This method is primarily designed to monitor system state. */ public final booleanhasQueuedThreads() {
        returnsync.hasQueuedThreads(); } /** * queries whether a given thread is waiting to acquire this lock. * Note that since cancellation can happen at any time, return {@codetrue} does not guarantee that the thread will acquire the lock. * This method is primarily designed to monitor system state. */ public final boolean hasQueuedThread(Thread thread) {returnsync.isQueued(thread); } /** * returns an estimate of the number of threads waiting to acquire this lock. * This value is only an estimate because the number of threads may change dynamically as this method iterates through the internal data structure. * This method is designed for monitoring system state, not for synchronous control. */ public final intgetQueueLength() {
        returnsync.getQueueLength(); } /** * returns a collection of threads that might be waiting to acquire this lock. * Because the actual set of threads may vary dynamically when constructing this result, the returned set is just a best guess. * The elements of the returned collection are in no particular order. * This method is designed to facilitate the construction of subclasses to provide broader monitoring capabilities. * */ protected Collection<Thread>getQueuedThreads() {
        returnsync.getQueuedThreads(); } /** * queries if there are any threads waiting for a given condition associated with this lock. * Please note that since timeouts and interrupts can happen at any time, {@codetrue} return does not guarantee that {@code signal} will wake up any thread in the future. * This method is primarily designed to monitor system state. */ public boolean hasWaiters(Condition condition) {if (condition == null)
            throw new NullPointerException();
        if(! (condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner");
        returnsync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } /** * returns an estimate of the number of threads waiting for a given condition associated with this lock. * Please note that since timeouts and outages can occur at any time, the estimates are only used as upper limits for the actual number of waiters. * This method is designed for monitoring system state, not for synchronous control. */ public int getWaitQueueLength(Condition condition) {if (condition == null)
            throw new NullPointerException();
        if(! (condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner");
        returnsync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } /** * returns a collection of threads that might be waiting for a given condition related to this lock. * Because the actual set of threads may vary dynamically when constructing this result, the returned set is just a best guess. * The elements of the returned collection are in no particular order. * This method is designed to facilitate the construction of subclasses that provide a broader range of status monitoring tools. */ protected Collection<Thread> getWaitingThreads(Condition condition) {if (condition == null)
            throw new NullPointerException();
        if(! (condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner");
        returnsync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); } /** * returns a string identifying this lock and its lock status. * the status in brackets includes the string {@code "Unlocked"} or the string {@code "Locked by"} that owns the thread, followed by {@linkplain Thread# getName name}. */ public StringtoString() {
        Thread o = sync.getOwner();
        return super.toString() + ((o == null) ?
                                   "[Unlocked]" :
                                   "[Locked by thread " + o.getName() + "]"); }}Copy the code