ReentrantLock
ReentrantLock implements Lock. There are many other implementations of locks under Lock, such as read locks and write locks.
ReentrantLock is a re-entry lock as well as a mutex lock. Lock implementation is based on internal class FairSync (fair lock) and NonFairSync (unfair lock).
Re-entry lock: The current thread acquires the lock of the execution sequence, so all the methods in the execution sequence can acquire the lock. Simply speaking, the thread acquires the lock to execute a resource, and the resource class department can still acquire the lock.
Mutex Locks: At most one thread can acquire a lock at a time. Both synchronize keywords and Lock are mutexes.
Fair Lock: Based on AQS (AbstractQueued Synchronizer) synchronizer queue implementation, the queue maintains Node (node), the value maintained in each node is the current thread requesting the lock (I feel it is a two-way linked list), the queue follows FIFO (first in first out), fair lock is only fetching value from the head of the queue at a time, the new thread first. Queue waiting
Unfair locks: Unfair locks are also implemented based on AQS, but when new threads join, the contention for locks occurs again, not for queuing operations. New threads are able to acquire locks to a large extent, while threads in the original queue will not be awakened and continue to wait. When new threads fail to acquire locks, they will join the queue. Threads in FIFO still follow FIFO.
Lock implementation mechanisms are implemented through node nodes, state locks, and cas e operations.
For more information, please check Detailed Implementation of Fair Locks and Unfair Locks in Java
All the source code I have directly removed the English comment, otherwise that comment too much I, the key is that I do not understand, need to use software translation, line by line, I will annotate a general meaning.
First, look at the source code of Lock class:
package java.util.concurrent.locks; import java.util.concurrent.TimeUnit; public interface Lock { // Locking and acquiring locks are commonly used in this method void lock(); void lockInterruptibly() throws InterruptedException; //Attempt to acquire locks, success or failure depends on God's will boolean tryLock(); //Attempt to acquire a lock in an event segment, see God's will if it fails boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //The release lock method is commonly used. void unlock(); // This condition is a very useful tool. Later on, the method in it is similar to object wait, notify, notify All. Condition newCondition(); }
ReentrantLock implements lock. Look at the source code of ReentrantLock:
Notes should be clearer
package java.util.concurrent.locks; import java.util.concurrent.TimeUnit; import java.util.Collection; public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; /** Sync implements aqs for one of the following internal classes */ private final Sync sync; /** * aqs It is the basis of synchronization control of this lock. The following are subdivided into fair and unfair versions. Use AQS status to indicate the number of locks retained. * sync For the ReentrantLock inner class, sync inherits AQS AQS and maintains Node nodes. The state lock holds state = 0. No thread holds the lock > 0. Threads hold the lock. The operation of state is a cas e operation. * */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * Execute {@link Lock # lock}. The main reason for subclassing is to provide fast paths for unfair versions. */ abstract void lock(); /** * Implement unfair tryLock. tryAcquire is implemented in subclasses, but it requires unfair attempts at trylock methods. * state Summary of attributes: * 1. Because there is multithreaded competition, use CAS to set values * 2. state The initial value is 0, the thread is locked once, the state is added 1, the thread that gets the lock is locked again, and the state value is added 1 again. So state indicates the number of locks that have been performed by the lock thread. * 3. Is a volatile-modified variable that threads read directly from main memory */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); //Lock status identifies a state in aqs that maintains an initial value of 0 state visible to all threads if (c == 0) { //The state is 0. if (compareAndSetState(0, acquires)) { //cas atom update operation, the object in memory and the expected value of 0 is equal, then the value is replaced by acquires, here do not understand the cas and so on. setExclusiveOwnerThread(current); //Set the current thread to the thread that currently has exclusive access return true; //Return to true } }else if (current == getExclusiveOwnerThread()) { //Determine whether the current thread has exclusive access to the thread int nextc = c + acquires; if (nextc < 0) // Overflow status less than 0, overflow throw new Error("Maximum lock count exceeded");//Throw an exception "Out of the Maximum Lock Count" setState(nextc);// If it is a thread that acquires a lock, get the lock again, and set it directly using the set method. return true; } return false; } //The release lock state-1 is actually protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread())//This operation is only for threads currently holding locks throw new IllegalMonitorStateException();//Otherwise, report wrong. boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } protected final boolean isHeldExclusively() { // When we must in general read state before owner, we generally have to check the status of the current thread // we don't need to do so to check if current thread is owner, but we don't need to do this to check if the current thread is the owner of the lock. return getExclusiveOwnerThread() == Thread.currentThread(); //Determine whether the current thread is a thread holding a lock } final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } //Check the status of thread holding locks final int getHoldCount() { //The current thread holds a lock, returns state, or returns 0 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 * ReentrantLockde Unfair Lock Internal Class is Unfair Lock Synchronization Object */ 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)) //Getting locks directly from atomic operations setExclusiveOwnerThread(Thread.currentThread());//Success directly sets the current thread as the lock holder else acquire(1); //Failure is added to the synchronous queue, the method in aqs, which calls tryAcquire(int acquires) and acquireQueued (Node, arg) } //Rewriting the tryAcquire Method of aqs protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); //An unfair method of acquiring locks by calling aqs directly } } /** * ReentrantLockde Fair Lock Internal Class is Fair Lock Synchronization Object */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * A Fair tryAcquire Method for Rewriting aqs */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && // hasQueuedPredecessors(), to determine whether this high-speed thread is the first in the queue, not the first to ensure that both new and queued threads use locks sequentially. 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 an unfair lock public ReentrantLock() { sync = new NonfairSync(); } //To create a fair lock or an unfair lock, depending on your choice, passing in true is a fair lock. public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } // public void lock() { sync.lock(); } //Attempt to acquire the lock, and return true if the lock is acquired public boolean tryLock() { return sync.nonfairTryAcquire(1); } //Gets the lock in the specified time class, if the acquisition returns true public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } //Release lock public void unlock() { sync.release(1); } // public Condition newCondition() { return sync.newCondition(); } //Gets the number of locks held by the current thread public int getHoldCount() { return sync.getHoldCount(); } //Check whether the current thread is a thread holding a lock public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } //Are locks held by threads public boolean isLocked() { return sync.isLocked(); } // public final boolean isFair() { return sync instanceof FairSync; } //Return the lock holder, the thread currently holding the lock protected Thread getOwner() { return sync.getOwner(); } //Query whether there are threads in the queue waiting to acquire locks public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } //Determine whether a specified thread is waiting for a lock to be acquired in the queue public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } //Return queue length public final int getQueueLength() { return sync.getQueueLength(); } //Return all threads in the queue protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); } // public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } // public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } // protected Collection<Thread> getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); } // public String toString() { Thread o = sync.getOwner(); return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]"); } }
Detailed analysis and reference:
https://blog.csdn.net/qyp199312/article/details/70598480