ReentrantLock: reentrant lock

Reference link: https://www.bilibili.com/video/BV1ta4y1H73X AQS knowledge is required Reentrant means that when a single...
Lock
Fair lock and unfair lock
Construction method
attribute
method

Reference link: https://www.bilibili.com/video/BV1ta4y1H73X

AQS knowledge is required

Reentrant means that when a single thread executes, re entering the same subroutine is still thread safe.

If it is non reentrant, if A obtains A lock, it will cause A deadlock when it requests the lock again

In short, a thread can repeatedly obtain the lock n times without releasing, and respond to release n times when releasing.

Let's talk about the implementation of RenentrantLocak, a reentrant lock.

First, let's take a look at the inheritance relationship of RenentrantLocak, which implements the Lock interface, that is, it follows the abstract definition of the Lock interface.

public class ReentrantLock implements Lock, java.io.Serializable

Lock

Lock provides another synchronization operation mode different from synchronized.

More extensive operations, more flexible structures can be supported, and multiple Condition objects can be associated.

// Acquire lock void lock(); // Obtain the lock. If it is interrupted while waiting for the lock, exit the wait and throw an exception void lockInterruptibly() throws InterruptedException; // Try to acquire the lock and return immediately boolean tryLock(); // An attempt to acquire a lock is made over a period of time. If the lock is interrupted, an interrupt exception will be thrown boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // Release lock void unlock(); // Create a new Condition object bound to the current Lock Condition newCondition();

Fair lock and unfair lock

Fair lock: it is allocated according to the request order of locks. For example, the FIFO mechanism in AQS implements fair locks

Unfair locks: locks are not allocated in the order in which they are requested, but there may be hunger in this way

Why design unfair locks?

In fact, the efficiency of unfair locks is often higher, which may improve the performance of concurrency.

When a thread wakes up, the thread state switching will have a short delay. The unfair lock mechanism allows the thread to preempt the lock during this event and quickly process the content.

This is one of the reasons why unfair locks perform better than fair locks.

Construction method

From the perspective of construction method, ReentrantLock is actually a Sync class. You can select FairSync and NonfairSync (default) through parameters.

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

attribute

final Sync sync

Sync is an internal abstract class of ReentrantLock, which inherits AQS

NonfairSync and FairSync are sub classes of Sync implementation, which are the implementation of non fair lock and fair lock respectively.

abstract static class Sync extends AbstractQueuedSynchronizer {...} static final class NonfairSync extends Sync {...} static final class FairSync extends Sync {...}

Back to Sync, you can notice that there is a nonfairTryAcquire(int acquires) method in Sync. You can know that it is a non fair lock method by name. Since it is implemented by NonfairSync and FairSync, why is this method defined in its parent class?

Let's take a look at this method:

final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 0 indicates that the lock state is idle, CAS can be used to obtain the lock // If the state change is successful, the lock is obtained if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // If the lock is occupied, judge whether the current thread is the thread holding the lock else if (current == getExclusiveOwnerThread()) { // Reentry, count + 1 int nextc = c + acquires; if (nextc < 0) // overflow, that is to prevent the number of threads from overflowing and becoming negative throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } // Lock not acquired return false; }
NonfairSync

NonfairSync implements the unfair lock mechanism by providing two preemptions:

  • Preemption during lock
  • Overridden tryAcquire calls nonfairTryAcquire
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; final void lock() { // Attempt to acquire lock [first preemption] if (compareAndSetState(0, 1)) // If successful, the lock is obtained setExclusiveOwnerThread(Thread.currentThread()); else // If it fails, the acquire method of AQS is called // Because the tryAcquire called in the acquire method is rewritten. // Therefore, the following trayAcquire method is called [Second preemption] acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
FairSync
static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { // Direct queue operation acquire(1); } // Override tryAcquire protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // Determine whether the lock is idle if (c == 0) { // You need to determine whether there is a pre waiting node if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // Reentry mechanism else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }

method

lock

It has been implemented in sync. You can call it directly.

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

trylock

public boolean tryLock() { return sync.nonfairTryAcquire(1); }

unlock

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

29 October 2021, 08:11 | Views: 5862

Add new comment

For adding a comment, please log in
or create account

0 comments