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

ReentrantLock source code analysis

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

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

This article introduces the relevant knowledge of "ReentrantLock source code analysis". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

1.ReentrantLock class diagram structure

We can know intuitively from the class diagram that ReentrantLock is finally implemented using AQS, and it is fair to determine its interior according to the parameters. Or unfair lock? the default is unfair lock.

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

Among them, the Sync class inherits directly from AQS, and its subclasses NonfairSync and FairSync implement the unfair and fair strategy of acquiring locks respectively.

If readers are not familiar with AQS, you can take a look at my article: abstract synchronization queue AQS--AbstractQueuedSynchronizer Lock details

Here, the state status value of AQS represents the number of times the thread can acquire the lock, and by default, a value of 0 of state indicates that the current lock is not held by any thread. When a thread acquires the lock for the first time, it attempts to set the value of state to 1 using CAS

If the CAS succeeds, the current thread acquires the lock and records that the owner of the lock is the current thread. After the thread acquires the lock for the second time without releasing the lock, the state value is set to 2, which is the number of times it can be reentered.

When the thread releases the lock, it attempts to use CAS to subtract the state value by 1, and if the status value is 0 after minus 1, the current thread releases the lock.

two。 The main method of acquiring locks 2.1 void lock () method

Lock () acquires locks by changing state from 0 to n (reentrant locks can be accumulated). What is actually called is the lock method of sync, which is divided into fair and unfair.

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

In the above code, the lock () of ReentrantLock is delegated to the sync class, and choose whether the implementation of sync is NonfairSync or FairSync according to the created ReentrantLock constructor. First, take a look at the case of NonfairSync, a subclass of sync.

Final void lock () {if (compareAndSetState (0,1)) / / CAS sets the status value to 1 setExclusiveOwnerThread (Thread.currentThread ()); / / sets the holder of the lock to acquire (1) if the current thread else / / CAS fails; / / calls the acquire method of AQS, passing a parameter of 1}

The following is the core source code of AQS's acquire

Public final void acquire (int arg) {if (! tryAcquire (arg) & & / / call ReentantLock to rewrite the tryAcquire method acquireQueued (addWaiter (Node.EXCLUSIVE), arg) / / tryAcquire returns false to put the current thread in the AQS blocking queue selfInterrupt ();}

As mentioned earlier, AQS does not provide an available tryAcquire method, and the tryAcquire method needs to be customized by the subclass itself, so here the code calls the tryAcquire method overridden by ReentantLock. Let's take a look at the unfair lock. Realization of

Protected final boolean tryAcquire (int acquires) {return nonfairTryAcquire (acquires);} final boolean nonfairTryAcquire (int acquires) {final Thread current = Thread.currentThread (); int c = getState (); if (c = = 0) {/ / the current AQS status is 0. the default is 1, because the previous CAS failed, acquire the lock if (compareAndSetState (0quores)) {/ / CAS set the status value to 1 setExclusiveOwnerThread (current) / / set the holder of the lock to the current thread return true;}} else if (current = = getExclusiveOwnerThread ()) {/ / if the current thread is the owner of the lock int nextc = c + acquires;//, it will accumulate, because the reentrant if (nextc < 0) / / overflow// indicates that the number of reentrants overflowed throw new Error ("Maximum lock count exceeded") SetState (nextc); / / reset the state of the lock return true;} return false;// if the current thread is not the owner of the lock, it returns false, which is then placed in the AQS blocking queue}

The end of the unfair lock? And look back at how unfairness is reflected here. First of all, it is unfair to say that the thread that tries to acquire the lock first does not necessarily have priority over the thread that tries to acquire the lock later.

Instead, it uses a snatch strategy. So let's take a look at the fair lock. How to achieve fairness.

Protected final boolean tryAcquire (int acquires) {final Thread current = Thread.currentThread (); int c = getState (); if (c = = 0) {/ / the current AQS status is 0 if (! hasQueuedPredecessors () & & / / fairness policy, determine whether there is any other node in the queue, and ensure fair compareAndSetState (0, acquires)) {/ / CAS setting status setExclusiveOwnerThread (current) / / set the thread return true;}} else if (current = = getExclusiveOwnerThread ()) {/ / if the current thread is the owner of the lock int nextc = c + acquires;// reentrants + 1 if (nextc < 0) throw new Error ("Maximum lock count exceeded"); setState (nextc) / / reset the status of lock return true;} return false;}}

As shown in the code above, a fair tryAcquire policy is similar to an unfair one, except that the code adds the hasQueuedPredecessors () method before setting the CAS operation, which is the core code to achieve fairness. The code is as follows

Public final boolean hasQueuedPredecessors () {Node t = tail; / / Read fields in reverse initialization order Node h = head; Node s; return h! = t & & ((s = h.next) = = null | | s.thread! = Thread.currentThread ());} 2.2void lockInterruptibly () method

This method is similar to the lock () method, except that it responds to interrupts. If another thread calls the current thread's interrupt () method when the current thread calls the method, the thread throws an exception and returns

Public void lockInterruptibly () throws InterruptedException {sync.acquireInterruptibly (1);} public final void acquireInterruptibly (int arg) throws InterruptedException {if (Thread.interrupted ()) / / if the current thread is interrupted, an exception throw new InterruptedException () is thrown directly; if (! tryAcquire (arg)) / / attempts to get the resource doAcquireInterruptibly (arg); / / calls the AQS interruptible method} 2.3boolean tryLock () method

Attempts to acquire the lock, and if the current lock is not held by another thread, the current thread acquires the lock and returns true, otherwise it returns false. Note that this method does not cause current thread blocking

Public boolean tryLock () {return sync.nonfairTryAcquire (1);} 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;}

The above code is similar to the tryAcquire () method code for unfair locks, so tryLock () uses an unfair strategy.

2.4 boolean tryLock (long timeout, TimeUnit unit) method

Try to acquire the lock, which is different from tryLock () in that it sets the timeout, and returns false if the timeout is up and it is useless to acquire the lock. Here is the relevant code

Public boolean tryLock (long timeout, TimeUnit unit) throws InterruptedException {return sync.tryAcquireNanos (1, unit.toNanos (timeout)); / / call the tryAcquireNanos method of AQS} public final boolean tryAcquireNanos (int arg, long nanosTimeout) throws InterruptedException {if (Thread.interrupted () throw new InterruptedException (); return tryAcquire (arg) | | doAcquireNanos (arg, nanosTimeout);} private boolean doAcquireNanos (int arg, long nanosTimeout) throws InterruptedException {if (nanosTimeout)

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

Internet Technology

Wechat

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

12
Report