当前位置:网站首页>Detailed analysis of abstractqueuedsynchronizer (AQS) source code - Analysis of lock release and response interrupt locking processes
Detailed analysis of abstractqueuedsynchronizer (AQS) source code - Analysis of lock release and response interrupt locking processes
2022-06-21 08:32:00 【*Wucongcong*】
AQS Member method resolution - Release lock logic
1、unlock() Method : Release the lock
// be located ReentrantLock Class : Method of releasing the lock
public void unlock() {
// Release the lock
sync.release(1);
}
// be located AQS The static inner class of Sync in : How to actually release the lock
// RentrantLock.unlock() -> sync.release()
public final boolean release(int arg) {
// tryRelease Try to release the lock :
// true: The current thread has completely released the lock
// false: The current thread has not fully released the lock
if (tryRelease(arg)) {
// head Under what circumstances will it be created ?
// When the lock thread does not release the thread , When another thread wants to acquire the lock during the lock holding period , Other threads found that they could not acquire the lock ,
// And the blocking queue is empty , At this point, subsequent threads will build a for the current lock thread head node ( Encapsulate the locking thread into head)
// Subsequent threads are then appended to head After the node ( Become head My back drive )
Node h = head;
// Conditions 1:h != null establish , Describe the... In the queue head The node has been initialized ,ReentrantLock During use , There is too much thread contention ~
// Conditions 2:h.waitStatus != 0 establish , Show the current head It must have been inserted in the back node node ~
if (h != null && h.waitStatus != 0)
// Wake up the rear drive node ~
unparkSuccessor(h);
return true;
}
return false;
}
2、tryRelease(int releases) Method : Try to release the lock
// RenntrantLock Static inner class in Sync Medium tryRelease() Method
protected final boolean tryRelease(int releases) {
// Minus the released value ..
int c = getState() - releases;
// Conditions established : Indicates that the current thread is not locked , Throw an exception directly
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
// So let's go over here , It indicates that the current thread is the thread holding the lock
// free: Indicates whether the lock has been completely released , The default is false
boolean free = false;
// Conditions established : This indicates that the current thread has reached the condition of completely releasing the lock c == 0
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
// to update state value There is no concurrency , So no need CAS operation , Because only the thread holding the lock can execute here
setState(c);
return free;
}
3、unparkSuccessor(Node node) Method : The method of waking up the first node that can be awakened among the successor nodes of the current node
// AQS Medium unparkSuccessor Method
/** * Wake up the next node of the current node * @param node */
private void unparkSuccessor(Node node) {
// Get the status of the current node
int ws = node.waitStatus;
if (ws < 0) // -1 SIGNAL state
// Change to 0 Why : Because the current node has completed the task of waking up the subsequent nodes
compareAndSetWaitStatus(node, ws, 0);
// The first successor node of the current node
Node s = node.next;
// s When is equal to null?
// 1. The current node is tail Node time , s == null, Because in addWiter() Team entry method , There are three steps ,1. Set the... Of the current node prev Point to tail node
// 2. Set the current node cas Become tail node 3. The original queue's tail The node points to the current node , When the third step has not been carried out , The front node releases the lock , Called unparkSuccessor Method
// This may lead to s == null
// You need to find a node that can be awakened
// Condition 2 :s.waitStatus > 0, precondition :s != null
// establish : Show the current node The successor node of the node is the cancel state , You need to find a suitable node to wake up
if (s == null || s.waitStatus > 0) {
// Find nodes that can be waked up
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
// The above loop will find a distance from the current node The latest one can be awakened node,node You may not find ,node It could be null
}
// If you find the right one to wake up node, Wake up the node , Don't do anything if you can't find it
if (s != null)
LockSupport.unpark(s.thread);
}
Last article :AbstractQueuedSynchronizer(AQS) Detailed analysis of source code - Lock competitive resource analysis and The earlier part of this article , It's all introductions ReentrantLock Of lock() Lock mode , This locking method is Not responsive to interrupts , Let's analyze Can respond to interruptions Lock mode of :lockInterruptibly():
Expand :AQS Member method resolution ( Response interrupt locking logic )
4、lockInterruptibly() A locking method that can be interrupted by a response
// be located ReentrantLock Class : A locking method that can be interrupted by a response
public void lockInterruptibly() throws InterruptedException {
// You can compete for resources in response to interruptions
sync.acquireInterruptibly(1);
}
// be located AQS Medium acquireInterruptibly Method
// Compete for resources in response to interruptions
public final void acquireInterruptibly(int arg)
throws InterruptedException {
// If a thread is interrupted , Throws an exception directly
if (Thread.interrupted())
throw new InterruptedException();
// If the contention lock resource fails, execute doAcquireInterruptibly Method
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
// be located AQS Medium doAcquireInterruptibly Method
// This method is executed when the contention lock resource fails
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
// The current thread performs a queued operation
final Node node = addWaiter(Node.EXCLUSIVE);
// true: Indicates that an interrupt exception occurred in the current thread
// false: Indicates that the current thread has successfully obtained the lock resource
boolean failed = true;
try {
// Spin operation
for (;;) {
// Condition one holds : Indicates that the current node is head.next node head.next Nodes have the right to compete for locks at any time
// Condition 2 :tryAcquire(arg)
// establish : Explain the last one head The corresponding thread has released the lock ,head.next The thread corresponding to the node just gets the lock
// Don't set up : explain head The corresponding thread has not released the lock yet head.next Still need to be park...
if (p == head && tryAcquire(arg)) {
// What you need to do after you get the lock ?
// Set the current node to head node
setHead(node);
// The corresponding to the previous thread node.next The reference is set to null , Help the old head Out of the team
p.next = null; // help GC
// No exception occurred during lock acquisition of the current thread
failed = false;
return;
}
// shouldParkAfterFailedAcquire(p, node): What is this method for ? Does the current thread need to hang after it fails to acquire the lock spin ?
// Return value true: Indicates that the current thread needs to be suspended false: There is no need to suspend
// parkAndCheckInterrupt(): Prerequisite : The current thread needs to be suspended What is the function of this method ?
// Suspends the current thread , And the interrupt flag of the current thread is returned after waking up
// ( Wake up the :1. Wake up normally Other threads unpark 2. Other threads will also wake up if they give an interrupt signal to the currently suspended thread )
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
// If the current thread is awakened by an interrupt, an interrupt exception is thrown directly
throw new InterruptedException();
}
} finally {
// Conditions established : Indicates that the current thread failed to compete for lock resources but threw an interrupt exception
if (failed)
// Respond to the logic of leaving the queue
cancelAcquire(node);
}
}
5、cancelAcquire(Node node) Method : Cancel the specified node Take part in the competition
// AQS Medium cancelAcquire() Method
// Respond to interrupt dequeue logic , Because there is no out of queue operation when an interrupt exception is thrown
// Cancel the specified node Take part in the competition
private void cancelAcquire(Node node) {
// Empty judgment
// Ignore if node doesn't exist
if (node == null)
return;
// Because the queue has been cancelled , therefore node The current thread of the internal association is set to null Just fine
node.thread = null;
// Skip cancelled predecessors
// Get the current dequeue node The precursor node of
Node pred = node.prev;
// The main purpose of this process is to find a current node that is unqueued and then all the precursor nodes in the queue waitStatus<=0 The node of
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// Get the precursor next node
// 1. At present node node
// 2. It could be CANCELED node
Node predNext = pred.next;
// Will the current node The node status is set to cancel status
node.waitStatus = Node.CANCELLED;
/** * Currently unqueued node The location of the queue is different , Different exit strategies are implemented , Divided into 3 In this case : * 1. At present node It's the end of the team ,tail -> node * 2. At present node No head.next node , Neither tail node * 3. At present node yes head.next node */
// Condition one holds :node == tail, Show the current node It is the end of the queue node ,tail -> node
// Condition 2 :compareAndSetTail(node, pred) establish : Explain the modification tail The node is pred node
if (node == tail && compareAndSetTail(node, pred)) {
// modify pred.next -> null, complete node Out of the team
compareAndSetNext(pred, predNext, null);
} else {
// Save the state of the node
int ws;
// The second case : At present node No head.next node , Neither tail node
// Conditions for a :pred != head establish : Indicates that the current node is not head.next node
// Condition 2 :((ws = pred.waitStatus) == Node.SIGNAL || (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL)))
// Conditions 2.1:(ws = pred.waitStatus) == Node.SIGNAL establish : explain node The status of the precursor node of is SIGNAL, Don't set up : The status of the precursor node may be 0
// In extreme cases : The precursor has also cancelled the queue
// Conditions 2.2:(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL)) precondition : The state of the precursor node is not SIGNAL state
// Suppose the precursor state is <= 0 Set the precursor status to SIGNAL state , Indicates to wake up the successor node
// if What's done inside , Is to make pred.next -> node.next, So make sure that pred The node status is SIGNAL state
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
// situation 2: At present node No head.next node , Neither tail node
// Out of the team :pred.next -> node.next After node , When node.next After being awakened , call shouldParkAfterFailedAcquire The method will make node.next Node crosses node in cancelled state
// Complete the real departure
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
// The third case : At present node yes head.next node , Wake up its successor nodes directly
// Similar situation 2: After the subsequent node is awakened , Would call shouldParkAfterFailedAcquire Ways to make node.next Cross the node in the cancelled state
// The third node in the queue will be directly connected to head Establish a dual direction relationship
unparkSuccessor(node);
}
// Point the subsequent pointer to itself , help GC
node.next = node; // help GC
}
}
summary :
- AQS Almost JAVA A basic framework for almost all locks and synchronizers in , here “ almost ”, Because very few did not pass AQS To achieve ;
- AQS A queue is maintained in , This queue is implemented using a two-way linked list , Used to hold threads waiting for locks to queue ;
- AQS A state variable is maintained in , Controlling this state variable can realize the lock and unlock operation ;
- be based on AQS It is very easy to write a lock by hand , Just implement AQS Just a few ways .
边栏推荐
- Ads Filter Design Wizard tool 2
- Listing of flaunting shares on Shenzhen Stock Exchange: market value of 4.2 billion, 9-month revenue decreased by 21% year-on-year
- 写文章的markdown规则
- Summary of mobile application development
- Decrypt FTP
- The market value of Jinshan office fell below 100 billion yuan: the shareholder Qiwen n-dimensional cash out exceeded 1.2 billion yuan
- 4.7 Inquirer. JS usage example
- Dumping backup database
- WordPress media library supports uploading and previewing SVG icons
- Doc common syntax, updating
猜你喜欢

antd table长表格如何出现滚动条

What aspects should the enterprise multimedia exhibition hall design start from

日记(C语言总结)

How to build a deep learning framework?

Fd: file descriptor

What should I do if a white page appears during MySQL installation

Yunkang group passed the hearing: the revenue exceeded 1billion in 8 months and the profit within the period was 270Million

This article takes you to interpret the advertising advantages of tiktok

LeetCode数组经典题目(一)

Haidilao is expected to have an annual net loss of 3.8 billion to 4.5 billion and close more than 300 stores
随机推荐
Mono fourni avec l'unit é 5 peut également supporter C # 6
[yuanuniverse 3D competition]
Visual studio code annotation plug-in: korofileheader
Audio immersive experience
TiDB、mysql修改系统变量/常用语句(杀死process中的进程)
Given a two-dimensional list of m*n, find out whether a number exists
4.5 dataset usage document
An aunt's towel holds up the 100 billion market behind 400million Chinese women
Redis master-slave vulnerability and remote connection vulnerability
Images, graphics and Applications (II)
Blue Bridge Cup: Candy
Leedcode 1 - sum of two numbers
Using elastic stack to analyze Olympic data (II)
给两个字符串s和t,判断t是否为s的重新排列后组成的单词
33 Jenkins modify plug-in source
GQL+Nodejs+MySQL数据库
The market value of Jinshan office fell below 100 billion yuan: the shareholder Qiwen n-dimensional cash out exceeded 1.2 billion yuan
PS prompts "script error -50 general Photoshop error, how to solve it?
Extensions in kotlin
Global and Chinese market for packed gas chromatographic columns 2022-2028: Research Report on technology, participants, trends, market size and share