Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How is ReentrantLock implemented and what is the source code in Java?

2025-04-10 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

Java ReentrantLock is how to achieve and how the source code, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain in detail for you, people with this need can come to learn, I hope you can gain something.

A brief introduction to ReentrantLock

ReentrantLock is located in the juc package of Java and appears from JDK1.5. It is a lock based on the exclusive mode of AQS synchronization queue. ReentrantLock is more flexible to use than synchronized, and can control the logic of locking and unlocking. ReentrantLock, like synchronized, is a reentrant lock, providing two fair / unfair modes:

Fair lock: when multiple threads compete for locks, it will first determine whether there is a waiting thread node in the waiting queue. If so, the current thread will queue, and the lock acquisition order is in accordance with the absolute time order of the request, that is, FIFO.

Unfair lock: when a thread competes for a lock, no matter whether other thread nodes are queuing or not, it will first attempt to acquire the lock through CAS, and queue up only if the acquisition fails.

The unfair lock is created by new ReentrantLock (). To create a fair lock, you need to specify new ReentrantLock (true) in the constructor. The common methods of ReentrantLock are as follows:

Void lock () acquires the lock. If the current thread succeeds in acquiring the lock, it will return. The thread that failed to acquire the lock will be blocked and suspended.

The void lockInterruptibly () throws InterruptedException interruptible lock acquisition differs from the lock method in that it responds to interrupts, that is, the current thread can be interrupted during lock acquisition

Boolean tryLock () attempts to acquire the lock without blocking, and the method returns immediately. If the lock is acquired successfully, it returns true, otherwise it returns false.

Boolean tryLock (long time, TimeUnit unit) throws InterruptedException attempts to acquire a lock within the specified timeout period. If the current thread acquires the lock, it will immediately return true, and if another thread acquires the lock, it will be blocked and suspended. This method will return in the following three cases: 1, the lock was acquired within the timeout, and true;2 is returned, and the thread is interrupted within the timeout; 3, the timeout ends and false is returned.

Void unlock () releases the lock

Condition newCondition () gets the waiting notification component, which is bound to the current lock. Only when the current thread acquires the lock can the wait () method of Condition be called, and the lock will be released after calling the wait () method.

II. Use of ReentrantLock

The use of ReentrantLock is generally as follows. Be sure to unlock it in finally to prevent the program from being unlocked when an exception occurs.

ReentrantLock lock = new ReentrantLock (); lock.lock (); try {System.out.println ("acquired lock");} catch (Exception e) {e.printStackTrace ();} finally {lock.unlock ();}

The following is a program example to demonstrate the use of ReentrantLock: lock and unlock the same lock object multiple times, and demonstrate the lock reentry of ReentrantLock.

Public class ReentrantLockTest {private Integer counter = 0; private ReentrantLock lock = new ReentrantLock (); public void modifyResources (String threadName) {System.out.println ("thread:-- >" + threadName+ "waiting for lock"); lock.lock (); System.out.println ("thread:-- >" + threadName+ "lock for the first time"); counter++ System.out.println ("Thread: + threadName+" do "+ counter+" thing "); / / reenter the lock. I have one more thing to do. I can't let the lock resources out until I'm done. Lock.lock (); System.out.println (" Thread:-- > "+ threadName+" Lock the second time "); counter++ System.out.println ("thread:" + threadName+ "do" + counter+ "thing"); lock.unlock (); System.out.println ("thread:" + threadName+ "release a lock"); lock.unlock (); System.out.println ("thread:" + threadName+ "release a lock");} public static void main (String [] args) throws InterruptedException {ReentrantLockTest tp = new ReentrantLockTest () New Thread (()-> {String threadName = Thread.currentThread (). GetName (); tp.modifyResources (threadName);}, "Thread: Zhang San") .start (); new Thread (()-> {String threadName = Thread.currentThread (). GetName (); tp.modifyResources (threadName);}, "Thread: Li Si"). Start () Thread.sleep;}}

The output of the program is as follows: in the above code, lock is locked twice and then unlocked twice. Li Si thread has been waiting before Zhang Sanshu unlocked twice. ReentrantLock locks several times and must be unlocked the same number of times before the lock can be released.

Thread:-- > Thread: Zhang San waits to acquire the lock

Thread:-- > Thread: Zhang San locked for the first time

Thread: Thread: Zhang San does the first thing

Thread:-- > Thread: Zhang San added locks for the second time

Thread:-- > Thread: Li Si waits to acquire the lock

Thread: Thread: Zhang San does the second thing

Thread: Thread: Zhang San releases a lock

Thread: Thread: Zhang San releases a lock

Thread:-- > Thread: Li Si added the lock for the first time

Thread: Thread: Li Si does the third thing

Thread:-- > Thread: Li Si added the lock for the second time

Thread: Thread: Li Si does the fourth thing

Thread: Thread: Li Si releases a lock

Thread: Thread: Li Si releases a lock

Third, ReentrantLock source code analysis

ReentrantLock implements the Lock interface, which has an inner class Sync that implements the AbstractQueuedSynchronizer described earlier, and its fair and unfair locks are implemented through the subclasses FairSync and NonFairSync of Sync (which is also the inner class of ReentrantLock). Let's take a look at its UML diagram.

The sequence diagram of the lock () method call is as follows:

The previous "Java concurrent programming JUC concurrent core AQS synchronous queue principle analysis" when introducing AQS, it was said that there is a state variable state in AbstractQueuedSynchronizer. In ReentrantLock, state equals 0 means there is no thread to acquire the lock. If it is equal to 1, it means that a thread has acquired the lock. If it is greater than 1, the thread that acquires the lock must be unlocked several times. Every time unlock unlocks the state, it will be reduced by 1, and the lock will be released when reduced to 0.

1. Analysis of unfair locking source code

The previous blog "Java concurrent programming JUC concurrent core AQS synchronous queue principle analysis" has introduced AQS in great detail, so the following source code analysis involving AQS methods will no longer be introduced, if you want to know, you can take a look at that blog.

Let's first take a look at the locked lock method of unfair locks. The lock method of sync is called in the lock method, and the sync object is constructed according to whether the ReentrantLock is FairSync or NonFairSync.

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

The unfair lock is called here, so let's take a look at the lock method of NonFairSync: no matter whether or not other threads hold or wait for the lock, the compareAndSetState method in AQS will be called first to attempt to acquire the lock. If the acquisition fails, the acquire method in AQS will be called.

Final void lock () {/ * the first step: try locking directly * one of the biggest differences between locking and fair locking is that it does not determine whether there are nodes in the synchronization queue (CLH queue) waiting to be locked directly (to determine whether state is 0MCAS and modify state to 1) * And point the exclusive lock holder exclusiveOwnerThread attribute to the current thread * if someone currently occupies the lock, try to add the lock again * / if (compareAndSetState (0,1)) setExclusiveOwnerThread (Thread.currentThread ()) The method defined by else / / AQS, locking acquire (1);}

Let's take a look at the acquire method. First, the tryAcquire method overridden in the NonFairSync class is called to attempt to acquire the lock. If the lock is not acquired, the acquireQueued method in AQS is called for queuing, blocking and other processing.

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

Let's take a look at the tryAcquire method overridden in the NonFairSync class, where the nonfairTryAcquire method is called

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

Take a look at the nonfairTryAcquire method:

Determine that if state is 0, try to acquire the lock through CAS. If the lock is acquired successfully, the current thread is set to exclusive thread.

If the state is not 0, determine whether the current thread is the same thread as the exclusive thread, and if it is the same thread, increase the lock state by 1, that is, increase the number of reentrants of the lock by 1.

Otherwise, failed to acquire the lock and return false

Final boolean nonfairTryAcquire (int acquires) {/ / acquires = 1 final Thread current = Thread.currentThread (); int c = getState () / * there is no need to determine whether there is a queue waiting thread in the synchronization queue (CLH) * determine whether the state status is 0, otherwise lock * / if (c = = 0) {/ / unsafe operation Cas modifies state state if (compareAndSetState (0, acquires)) {/ / exclusive state lock holder points to the current thread setExclusiveOwnerThread (current) Return true;}} / * state status is not 0, determine whether the lock holder is the current thread, * if the current thread holds it, then state+1 * / else if (current = = getExclusiveOwnerThread ()) {int nextc = c + acquires If (nextc < 0) / / overflow throw new Error ("Maximum lock count exceeded"); setState (nextc); return true;} / / Lock failed return false;}

Let's look at the unlocking process of the unfair lock: the release method in AQS is called in the unlock method.

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

The release method in AQS is as follows: first, the tryRelease method overridden in the subclass Sync of AQS is called to release the lock. If the lock is successful, the subsequent nodes of head in the synchronization queue are awakened, and the subsequent node thread will compete for the lock when it is awakened.

Public final boolean release (int arg) {if (tryRelease (arg)) {/ / release the one-time lock Node h = head; if (h! = null & & h.waitStatus! = 0) unparkSuccessor (h); / / wake up the successor node return true;} return false;}

The tryRelease method overridden in Sync:

Get the current state value, and then subtract 1

Determines whether the current thread is the holding thread of the lock, and if not, an exception is thrown.

If the value of state is reduced to 0, indicating that the lock has been released, the exclusive thread is set to empty null, state is set to 0, true is returned, otherwise false is returned.

/ * release lock * / 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;} 2. Analysis of Fair Lock Source Code

Let's first take a look at the locked lock method of fair lock. The lock method of sync is called in the lock method, and the lock method of FairSync is called here.

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

The lock method of FairSync directly calls the acquire method in AQS, instead of trying to acquire the lock first through CAS like the unfair lock.

Final void lock () {acquire (1);}

Let's take a look at the acquire method. First, the tryAcquire method overridden in the FairSync class is called to attempt to acquire the lock. If the lock is not acquired, the acquireQueued method in AQS is called for queuing, blocking and other processing.

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

Let's take a look at the tryAcquire method overridden in the FairSync class. The only difference between this method and NonFairSync is that when state is 0, the fair lock will first determine whether there is a waiting node in the queue through the hasQueuedPredecessors () method. If not, it will try to acquire the lock through CAS, and the unfair lock will not determine whether it will directly attempt to acquire the lock.

Protected final boolean tryAcquire (int acquires) {final Thread current = Thread.currentThread (); int c = getState () Differences between if (c = = 0) {/ * and unfair locks You need to determine whether there are waiting nodes in the queue * if not, you can try CAS to acquire the lock * / if (! hasQueuedPredecessors () & & compareAndSetState (0) Acquires) {/ / exclusive thread points to the current thread 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;}

The unlock method of fair locks is the same as the code of unfair locks, which is not covered here.

Is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report