当前位置:网站首页>In depth understanding of condition source code interpretation and analysis of concurrent programming
In depth understanding of condition source code interpretation and analysis of concurrent programming
2022-07-01 05:25:00 【Jackli1123 (cross correlation second return)】
Deep understanding of concurrent programming Condition Source code analysis
List of articles
One 、Condition What is it?
Condition It's an interface , It provides two core methods ,await() and signal() Method , amount to Object Of wait and notify Method , perform await() Method to enter the waiting state of the thread will be placed in Condition In the single queue of . Note that both the wait and wake methods need to be executed between the code blocks of the lock .
- firstWaiter:Condition The first person in the queue
- lastWaiter:Condition The last person in the queue
- await(): The current thread is waiting
- signal(): Wake up a waiting thread
- signalAll(): Wake up all waiting threads
Two 、Condition Detailed analysis
1. Illustrate with examples Condition Usage of
public class Test {
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " Thread gets lock ");
condition.await();
System.out.println(Thread.currentThread().getName() + " End of thread execution ");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
try {
Thread.sleep(3000);
} catch (Exception e) {
}
lock.lock();
condition.signal(); // Wakes up the waiting thread , Wakes up but does not execute , Because the lock tag is now held by the main thread
System.out.println(Thread.currentThread().getName() + " End of main thread execution ");
lock.unlock(); //lock The lock needs to be released , Threads 0 Only when the lock tag is obtained can it be executed
}
}
Take a look at the execution results , At the beginning, the thread executes printing and obtains the lock , Yes await() Method entry wait , sleep 3 Seconds passed , The main thread acquires the lock ( Because the lock mark will be released after entering the blocking state ), When the main thread is finished , Release the lock and the sub thread continues to execute from the waiting place , It should be noted here that the main thread will always be locked if it does not release the lock mark Blocked state , Because the lock mark is not found at all :
1.Condition Source code analysis
await()
Have a look first condition Waiting method source code
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter(); //Condition Add a waiting person to the waiting queue
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
// If the current thread's waitStatus Status as -2 Wait state , Then execute the loop . The state of the node creating the waiting queue must be -2
LockSupport.park(this); // Blocking the current thread
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) // The corresponding interrupt jumps out of the loop
break;
}
//acquireQueued in front Lock Also talked about , Is to perform lock() Method , Inside first CAS Try to acquire the lock. If the lock cannot be acquired, it will enter the blocking state . When multiple threads wake up at the same time, they will enter lock Blocked state , Here's the original state The status has been modified
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // There is no next waiting person to clear
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
/** 1. Add the method of waiting */
private Node addConditionWaiter() {
Node t = lastWaiter; // First time in t It's empty
if (t != null && t.waitStatus != Node.CONDITION) {
// If the last node is not empty and the state is not waiting, clean up the threads in the blocking queue that are not waiting
unlinkCancelledWaiters();
t = lastWaiter;
}
// Create a node of the current thread and hang it at the back of the waiting queue
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node; // You can see from here that , Only next But not pred explain Condition The queue of is one-way
lastWaiter = node;
return node; // Returns the node of the current thread
}
/** 2. Try to release the lock mark of the current thread and return to the original state , because lock The lock is reentrant , therefore state The value of is uncertain */
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState(); // Get the original state state
if (release(savedState)) {
// The current thread is unlocked , This is in Lock Of unlock() The method has already been discussed
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
/** 3. Will wait for the current wait -2 The status node is modified to 0 Waiting for lock status */
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
// At this time, the modification status is changed by -2 Turned into 0, Waiting becomes blocked
enq(node); // Here, the current node is added to the blocking queue
return true;
}
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
Sum up await() Steps for :
- stay Condition Add the current thread as one of the waiters
- Try to make the current thread release the lock mark and record the current thread's state
- Change the status of the current thread node to -2 Wait state , Then block the current thread until the interrupt response obtains the lock mark and is awakened
- The interrupt response jumps out of the loop , Will thread the state state ( Number of re-entry locks ) Change to the original state .
signal()
Have a look first condition Wake up method source code :
/** 1. Wake up the first one waiting */
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
/** 2. Wake up the first one waiting */
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null) // It is judged here that if the first node is the next node of the first , Then there is a waiting , Empty
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
/** 3. Set the current thread to 0 Blocked state , And join the last node in the blocking queue */
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) // Change the status from -2 Turn into 0, Waiting becomes blocked
return false;
Node p = enq(node); // Set the current node as the last node in the blocking queue
int ws = p.waitStatus;
// If the node state >0, Just see if the lock tag is held by the current thread , Is to discard the lock tag , Generally, it will not wait for the thread to hold the lock mark
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
The method of awakening is relatively simple , Briefly describe what you did
- Change the state of the first node from -2 The waiting status is changed to 0 Blocked state
- Add this node to the blocking queue , Just wait to get the lock mark
Let's take a look at the following diagram to assume T1,T2,T3 How the three threads execute , hypothesis t2 Wait first , then t3 The wait method is executed again , Yes in the waiting pool t2 and t3, At this point, it wakes up t2, be t2 Entered the blocking queue , It is not directly implemented , Because I just wake up and haven't got the lock mark yet .
Content sources : Ant class
边栏推荐
- Design and application of immutable classes
- Worried about infringement? Must share copyrightless materials on the website. Don't worry about the lack of materials for video clips
- 轻松上手Fluentd,结合 Rainbond 插件市场,日志收集更快捷
- El cascade echo failed; El cascader does not echo
- Print stream and system setout();
- 导电滑环短路的原因以及应对措施
- 0xc000007b the application cannot start the solution normally (the pro test is valid)
- Set集合詳細講解
- Implementation of distributed lock
- 云原生存储解决方案Rook-Ceph与Rainbond结合的实践
猜你喜欢

云原生存储解决方案Rook-Ceph与Rainbond结合的实践

Leetcode1497- check whether array pairs can be divided by K - array - hash table - count

Practice of combining rook CEPH and rainbow, a cloud native storage solution

tar命令

Tar command

Application and principle of ThreadPoolExecutor thread pool

El cascade echo failed; El cascader does not echo

Explanation of characteristics of hydraulic slip ring
![[RootersCTF2019]babyWeb](/img/b4/aa8f8e107a9dacbace72d4717b1834.png)
[RootersCTF2019]babyWeb

Design and application of immutable classes
随机推荐
Global and Chinese markets of gps/gnss receiver modules 2022-2028: Research Report on technology, participants, trends, market size and share
云原生存储解决方案Rook-Ceph与Rainbond结合的实践
Vmware workstation network card settings and three common network modes
Rainbow combines neuvector to practice container safety management
Software intelligence: the "world" and "boundary" of AI sentient beings in AAAs system
AcWing 888. Finding combinatorial number IV (the problem of finding combinatorial number with high precision)
El cascade echo failed; El cascader does not echo
[RootersCTF2019]babyWeb
C WPF uses dockpanel to realize screenshot box
Distributed transactions - Solutions
Design and application of immutable classes
Global and Chinese market of 3D CAD 2022-2028: Research Report on technology, participants, trends, market size and share
Use and principle of wait notify
HCIP Day13
使用 Nocalhost 开发 Rainbond 上的微服务应用
了解 JVM 中几个相关问题 — JVM 内存布局、类加载机制、垃圾回收
Go learning notes (5) basic types and declarations (4)
Copy baby prompt: material cannot be empty. How to solve it?
Print stream and system setout();
Vérification simple de la lecture et de l'écriture de qdatastream