AQS
AbstractQueuedSynchronizer
Copy the code
concerns
Node
A first-in, first-out queueCopy the code
volatile int state
Marks whether or how many times the current lock has been acquired (reentrant lock)Copy the code
tryAcquire()
Exclusive lock uses an attempt to acquire lock method that needs to be subclass overriddenCopy the code
tryRelease()
The attempt to release lock method used by exclusive locks needs to be subclass overriddenCopy the code
tryAcquireShared()
The shared lock uses an attempt to acquire lock method that needs to be subclassedCopy the code
tryReleaseShared()
The attempt to release lock method used by the shared lock needs to be subclassedCopy the code
ReentrantLock
There is a member variable Sync Sync implements AQS interface 1. 2. AQS synchronizer is usedCopy the code
The sample code
private Lock lock = new ReentrantLock();
public void method(a) {
lock.lock();
try {
Thread.sleep(1000);
System.out.println("hello");
} catch (Exception e) {
e.printStackTrace();
} finally{ lock.unlock(); }}Copy the code
ReentrantLock constructor
public ReentrantLock(a) {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
/* We can see from the above two constructors that it is possible to create different synchronizers depending on the constructor we choose or the arguments we pass. NonfairSync is unfair. FairSync is fair
Copy the code
lock()
// Call the lock method of different synchronizers according to different synchronizers
public void lock(a) {
sync.lock();
}
Copy the code
FairSync.lock()
final void lock(a) {
// This method is a parent of AQS
acquire(1);
}
public final void acquire(int arg) {
// The tryAcquire method should be subclassed
// Call the fairsync.tryacquire method because the current class is FairSync
// If tryacquire returns true, the && expression is not executed
If the tryAcqyire method returns false, it fails to acquire the lock, enters the wait queue and performs selfInterrupt to interrupt the current thread
if(! tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }/ / Java. Util. Concurrent. The locks. Already. FairSync. TryAcquire (int), the parameter value is 1
protected final boolean tryAcquire(int acquires) {
// Get the current thread
final Thread current = Thread.currentThread();
// Get the value of aqs. state, which is used to determine whether a thread has acquired the lock
int c = getState();
// If the value is 0, no thread has acquired the lock
if (c == 0) {
The hasqueuedToraise method determines whether a waiting thread exists on the wait queue (because it is a fair lock)
//compareAndSetState Specifies the state value for the CAS operation
/ / setExclusiveOwnerThread set the current thread of acquiring a lock for the current thread
// So this expression in if means:
If the CAS operation succeeded and the set thread succeeded, true is returned indicating that the lock was obtained
if(! hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true; }}// If the value of state is not 0, there are threads competing for the lock
// Determine whether the thread that acquired the lock is current (reentrant lock)
else if (current == getExclusiveOwnerThread()) {
// If state is accumulated, it represents the number of reentrant times
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
Copy the code
NonfairSync.lock()
final void lock(a) {
// Just try to get the lock (set state). This is the difference from a fair lock
if (compareAndSetState(0.1))
// If so, set the exclusive thread to the current thread
setExclusiveOwnerThread(Thread.currentThread());
else
// if not successful, call AQS acquire method, which mentioned above to tryAcquire directly
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// This method is basically the same as a fair synchronizer, the only difference is one line less
//hasQueuedPredecessors
// In other words, it is not fair to preempt the lock without determining whether there are waiting threads in the queue
// There are two places where an unfair lock preempts the lock directly, once in the lock method and once in the current method
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;
}
Copy the code
unlock()
Either a fair lock or an unfair lock is one way to do itCopy the code
public void unlock(a) {
sync.release(1);
}
// This is AQS release method
public final boolean release(int arg) {
// The tryRelease method that subclasses are required to implement, indicating whether to release the lock public
if (tryRelease(arg)) {
Node h = head;
if(h ! =null&& h.waitStatus ! =0)
// If the lock is released successfully and there are values in the wait queue
// Wake up a thread
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
// The value of state is -1
int c = getState() - releases;
// An error is reported if the thread releasing the lock is different from the thread holding the lock
if(Thread.currentThread() ! = getExclusiveOwnerThread())throw new IllegalMonitorStateException();
boolean free = false;
// If state is 0, the lock is released successfully
if (c == 0) {
free = true;
// Set the exclusive thread to NULL
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
Copy the code