The principle and partial source code analysis of ReentrantLock in Java

I've been working on locks in jdk recently. Let's talk about it below.

The Lock interface is provided in the Java concurrency package to implement the lock function. Provides synchronization functionality similar to synchronized. It is only necessary to explicitly acquire and release locks when using them. Although it lacks the convenience of implicitly acquiring locks, it has

The operability of lock acquisition and release, the interruptible acquisition of locks, and the timeout acquisition of locks, and other synchronization features that synchronized does not have.

1. Queue Synchronizer

     The queue synchronizer AbstractQueuedSynchronizer is a basic framework for building locks or other synchronization components. It uses an int member variable to represent the synchronization state, and completes the queuing of resource acquisition threads through the built-in FIFO queue.

The synchronizer can support both exclusive acquisition of synchronization status and shared acquisition of synchronization status.

Let's talk about    the principle of exclusive    acquisition of the lock state

  Exclusively acquiring a lock will cause other threads to be blocked when competing for this one lock resource


ReentrantLock------>call lock()----------default non-fair lock------->call in NonfairSync, the non-fair synchronizer implemented inside ReentrantLock---- lock() as shown below


If the acquisition of the lock fails ---> call the acquire(int arg) method in the parent class AbstractQueuedSynchronizer synchronizer as shown in the figure


The logic of the above picture: I try to acquire the lock. If I can get it, the subsequent acquireQueued() does not need to be executed, and I get the lock directly. If the lock is not acquired, it returns false. Then, the following will be executed to construct the current thread as a node Node and put it in the synchronization queue. Let's see how tryAcquire(arg)


The method shown in the figure above is called internally by tryAcquire(arg). Explain what is in the picture. ---------->If it returns fasle------The current thread should be constructed as a Node node and placed in the synchronization queue---->The logic of adding a node is as follows


The addWaiter() method in acquireQueued(addWaiter(Node.EXCLUSIVE), arg) is to construct the current thread as a node Node. Put it into the synchronization queue, and Node is a reference to the current thread .

acquireQueued(). Acquiring the queue is to determine when the node gets the lock and returns by spinning



How to do blocking? In fact, when the thread does not get the lock, it is actually running all the time. It has been running the above spin judgment. If the lock is not obtained, it is equivalent to blocking in the queue and looping judgment all the time. Stopped at lock() lock acquisition here

The above is the realization principle of unfair lock;

Let me look at the implementation of fair locks.

The difference between fair locks and unfair locks is that when calling fair locks, there is no direct CAS atomic operation to try to set and modify the state to take the lock, but directly call acquire(1)--as shown in the figure



Lock release:

    The general principle: Get the state value c of the synchronizer, and then subtract 1 or the passed parameter arg. If c-1=0 or c-arg=0; then set the thread held by the synchronizer to null. And Set c to 0; as shown in the source code


This is the general principle of an exclusive lock. Please guide if there is something wrong.

--I think it is still necessary to study the synchronization queue.




 




Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324606506&siteId=291194637