当前位置:网站首页>[interview: concurrent Article 16: multithreading: detailed explanation of wait/notify] principle and wrong usage (false wake-up, etc.)
[interview: concurrent Article 16: multithreading: detailed explanation of wait/notify] principle and wrong usage (false wake-up, etc.)
2022-07-27 00:42:00 【I cream】
【 interview : Concurrent articles 16: Multithreading :wait/notify Detailed explanation 】 Principle and wrong usage ( False awakening, etc )
00. Preface
If there are any questions , Please point out .
01. Introduce
We had a simple understanding in the process of learning wiat/notify, But there is no systematic introduction wait/notify,wait Is to make the thread fall into waiting notify Is to wake up a person randomly wait The thread of .
02. working principle
When a thread acquires a lock But I find that I don't meet some conditions When a code block that locks a part cannot be executed Need to enter the waiting list Threads will not compete again until the conditions are met

The above figure shows its working principle
Be careful
1.Owner It is found that a thread does not meet the condition , call wait Method , At this point, the thread enters WaitSet, And the state of this thread changes to WAITING state
2.BLOCKED and WAITING Threads in state do not participate cpu Dispatch , Not occupy cpu Time slice
3.WAITING Thread will be Owner Thread calls notify or notifyAll Wake up when , But you still have to enter after waking up EntryList Re compete for locks
03.API Introduce
obj.wait():wait Method let in object Monitor thread to waitSet wait for .wait The object lock will be released after , Let other threads compete
obj.wait(Long timeout):wait Time bound method , If no other thread wakes up within the time limit , Then you directly wake yourself up , If another thread wakes up during this period, it wakes up normally .wait The object lock will be released after , Let other threads compete
obj.notify():notify The method is to make waitSet The waiting thread picks a wake-up
obj.notifyAll():notifyAll The method is to make waitSet All the waiting threads wake up
They are all means of collaboration between threads , All belong to Object Object methods , You must acquire the lock of this object , To call these methods , If you call these methods directly without locking, an error will be reported
notify And notifyAll Comparison of
@Slf4j(topic = "c.TestWaitNotify")
public class TestWaitNotify {
final static Object obj = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj) {
log.debug(" perform ....");
try {
obj.wait(); // Let the thread in obj Keep waiting on
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(" Other code ....");
}
},"t1").start();
new Thread(() -> {
synchronized (obj) {
log.debug(" perform ....");
try {
obj.wait(); // Let the thread in obj Keep waiting on
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(" Other code ....");
}
},"t2").start();
// The main thread executes in two seconds
sleep(0.5);
log.debug(" Wake up the obj On other threads ");
synchronized (obj) {
// obj.notify(); // Wake up the obj Last thread
obj.notifyAll(); // Wake up the obj All waiting threads on
}
}
}
result
call notify when :
23:11:55.798 c.TestWaitNotify [t1] - perform …
23:11:55.801 c.TestWaitNotify [t2] - perform …
23:11:56.300 c.TestWaitNotify [main] - Wake up the obj On other threads
23:11:56.300 c.TestWaitNotify [t1] - Other code …call notifyAll when :
23:12:26.195 c.TestWaitNotify [t1] - perform …
23:12:26.198 c.TestWaitNotify [t2] - perform …
23:12:26.699 c.TestWaitNotify [main] - Wake up the obj On other threads
23:12:26.699 c.TestWaitNotify [t2] - Other code …
23:12:26.699 c.TestWaitNotify [t1] - Other code …
explain
It can be seen that notify Is to wake up a thread at random ,notifyAll It wakes up all threads
04.wait And sleep Differences in methods
difference
1.sleep yes Thread Class method of , and wait yes Object The object method of
2.sleep There's no need to force and synchronized In combination with , however wait Need and synchronized Together with
3.sleep While sleeping , Object locks are not released , but wait The object lock will be released while waiting
4. Endless wait After method execution Thread becomes WAITING state , Time limited wait Methods and sleep After the method is executed, it becomes TIMED_WAITING state
Analyze the following code
@Slf4j(topic = "c.Test19")
public class Test19 {
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
log.debug(" Gets the lock ");
try {
// Thread.sleep(2000);
lock.wait(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1").start();
Sleeper.sleep(1);
synchronized (lock) {
log.debug(" Gets the lock ");
}
}
}
result
When calling sleep The case when :
23:20:48.788 c.Test19 [t1] - Gets the lock
When calling wait The case when :
23:21:27.759 c.Test19 [t1] - Gets the lock
23:21:28.768 c.Test19 [main] - Gets the lock
explain
The above results show that sleep During suspension It won't release the lock Lead to During this period, other threads cannot run , and wait Then the lock can be released
05.wait/notify Correct use of
Since it is the correct use , Then it needs to be done step by step , Gradually optimize the incorrect part .
Example illustrate
Now there is a group of people who need to work , One of them is Xiaonan He can't work until he smokes . Now is to simulate this problem .
Simulate a
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.TestCorrectPosture")
public class TestCorrectPostureStep1 {
static final Object room = new Object();
static boolean hasCigarette = false; // Is there any smoke
static boolean hasTakeout = false;
public static void main(String[] args) {
new Thread(() -> {
synchronized (room) {
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (!hasCigarette) {
log.debug(" No smoke , Take a break !");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (hasCigarette) {
log.debug(" You can start working ");
}
}
}, " Xiaonan ").start();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
synchronized (room) {
log.debug(" You can start working ");
}
}, " Other people ").start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
// Can you add synchronized (room)?
synchronized (room) {
// 33 That's ok
hasCigarette = true;
log.debug(" Here comes the smoke !");
}
}, " The cigarette man ").start();
}
}
result
33 OK, add it synchronized:
23:2516.146 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
23:25:16.149 c.TestCorrectPosture [ Xiaonan ] - No smoke , Take a break !
23:25:18.157 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
23:25:18.157 c.TestCorrectPosture [ The cigarette man ] - Here comes the smoke !
23:25:18.157 c.TestCorrectPosture [ Other people ] - You can start working
23:25:18.157 c.TestCorrectPosture [ Other people ] - You can start working
23:25:18.158 c.TestCorrectPosture [ Other people ] - You can start working
23:25:18.158 c.TestCorrectPosture [ Other people ] - You can start working
23:25:18.158 c.TestCorrectPosture [ Other people ] - You can start working33 Yes or no synchronized:
23:26:19.464 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
23:26:19.468 c.TestCorrectPosture [ Xiaonan ] - No smoke , Take a break !
23:26:20.475 c.TestCorrectPosture [ The cigarette man ] - Here comes the smoke !
23:26:21.470 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[true]
23:26:21.470 c.TestCorrectPosture [ Xiaonan ] - You can start working
23:26:21.471 c.TestCorrectPosture [ Other people ] - You can start working
23:26:21.471 c.TestCorrectPosture [ Other people ] - You can start working
23:26:21.471 c.TestCorrectPosture [ Other people ] - You can start working
23:26:21.471 c.TestCorrectPosture [ Other people ] - You can start working
23:26:21.471 c.TestCorrectPosture [ Other people ] - You can start working
explain
Let's analyze the defects of this simulation :
33 Yes or no synchronized:
When we don't add synchronized When we found the problem is Because Xiao Nan called sleep sleep 2s The lock is not released during So at this time, the code block locked by other threads cannot run , It makes others unable to work
33 Xingjia synchronized:
Danga synchronize At that time, the above problems remained unsolved , And there is a new problem , Xiao Nan is sleep 2s period The number of the main thread 33 OK, because I added synchronized Lead to hasCigarette It has not changed to true, So at this time, Xiao Nan is 1s After that, I didn't receive any smoke So Xiao Nan has no job
Simulation 2
It can be seen that the main problem of simulation one is Xiao Nan doesn't work Others have to wait , And Xiao Nan may be locked due to the cigarette delivery code block As a result, you can't receive cigarettes and don't work
We use it wait/notify To optimize
@Slf4j(topic = "c.TestCorrectPosture")
public class TestCorrectPostureStep2 {
static final Object room = new Object();
static boolean hasCigarette = false;
static boolean hasTakeout = false;
public static void main(String[] args) {
new Thread(() -> {
synchronized (room) {
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (!hasCigarette) {
log.debug(" No smoke , Take a break !");
try {
room.wait(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (hasCigarette) {
log.debug(" You can start working ");
}
}
}, " Xiaonan ").start();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
synchronized (room) {
log.debug(" You can start working ");
}
}, " Other people ").start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
synchronized (room) {
hasCigarette = true;
log.debug(" Here comes the smoke !");
room.notify();
}
}, " The cigarette man ").start();
}
}
result
23:30:41.080 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
23:30:41.083 c.TestCorrectPosture [ Xiaonan ] - No smoke , Take a break !
23:30:41.084 c.TestCorrectPosture [ Other people ] - You can start working
23:30:41.084 c.TestCorrectPosture [ Other people ] - You can start working
23:30:41.084 c.TestCorrectPosture [ Other people ] - You can start working
23:30:41.085 c.TestCorrectPosture [ Other people ] - You can start working
23:30:41.085 c.TestCorrectPosture [ Other people ] - You can start working
23:30:42.085 c.TestCorrectPosture [ The cigarette man ] - Here comes the smoke !
23:30:42.085 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[true]
23:30:42.086 c.TestCorrectPosture [ Xiaonan ] - You can start working
It seems that there is no problem , But what if there is another thread that needs conditions to work ?
Simulation three
Let's add another one to the previous topic figure Little girl , The little girl needs takeout to work , At this time, we will use the method of simulation two to simulate
@Slf4j(topic = "c.TestCorrectPosture")
public class TestCorrectPostureStep3 {
static final Object room = new Object();
static boolean hasCigarette = false;
static boolean hasTakeout = false;
// spurious wakeup
public static void main(String[] args) {
new Thread(() -> {
synchronized (room) {
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (!hasCigarette) {
log.debug(" No smoke , Take a break !");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (hasCigarette) {
log.debug(" You can start working ");
} else {
log.debug(" Didn't do it ...");
}
}
}, " Xiaonan ").start();
new Thread(() -> {
synchronized (room) {
Thread thread = Thread.currentThread();
log.debug(" Did the takeout arrive ?[{}]", hasTakeout);
if (!hasTakeout) {
log.debug(" No takeout , Take a break !");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Did the takeout arrive ?[{}]", hasTakeout);
if (hasTakeout) {
log.debug(" You can start working ");
} else {
log.debug(" Didn't do it ...");
}
}
}, " Little girl ").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
synchronized (room) {
hasTakeout = true;
log.debug(" Here's the takeout !");
room.notify();
}
}, " Take away delivery ").start();
}
}
result
23:45:35.476 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
23:45:35.486 c.TestCorrectPosture [ Xiaonan ] - No smoke , Take a break !
23:45:35.486 c.TestCorrectPosture [ Little girl ] - Did the takeout arrive ?[false]
23:45:35.486 c.TestCorrectPosture [ Little girl ] - No takeout , Take a break !
23:45:36.483 c.TestCorrectPosture [ Take away delivery ] - Here's the takeout !
23:45:36.483 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
23:45:36.483 c.TestCorrectPosture [ Xiaonan ] - Didn't do it …
explain
We found a new little girl after There is another problem with this code , At first Xiaonan The little girl can't work if she doesn't meet the conditions , But because notify Is to wake up a thread , Lead to It was supposed to wake up the little girl's thread Wake up Xiao Nan But he didn't give Xiao Nan the conditions he needed , And because of this, the little girl has no chance to have takeout activities , As a result, the little girl and the little girl didn't work
This situation of waking up threads that should not be awakened is called spurious wakeup
Simulation IV
@Slf4j(topic = "c.TestCorrectPosture")
public class TestCorrectPostureStep4 {
static final Object room = new Object();
static boolean hasCigarette = false;
static boolean hasTakeout = false;
public static void main(String[] args) {
new Thread(() -> {
synchronized (room) {
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (!hasCigarette) {
log.debug(" No smoke , Take a break !");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (hasCigarette) {
log.debug(" You can start working ");
} else {
log.debug(" Didn't do it ...");
}
}
}, " Xiaonan ").start();
new Thread(() -> {
synchronized (room) {
Thread thread = Thread.currentThread();
log.debug(" Did the takeout arrive ?[{}]", hasTakeout);
if (!hasTakeout) {
log.debug(" No takeout , Take a break !");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Did the takeout arrive ?[{}]", hasTakeout);
if (hasTakeout) {
log.debug(" You can start working ");
} else {
log.debug(" Didn't do it ...");
}
}
}, " Little girl ").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
synchronized (room) {
hasTakeout = true;
log.debug(" Here's the takeout !");
room.notifyAll();
}
}, " Take away delivery ").start();
}
}
result
00:00:01.274 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
00:00:01.274 c.TestCorrectPosture [ Xiaonan ] - No smoke , Take a break !
00:00:01.274 c.TestCorrectPosture [ Little girl ] - Did the takeout arrive ?[false]
00:00:01.274 c.TestCorrectPosture [ Little girl ] - No takeout , Take a break !
00:00:02.284 c.TestCorrectPosture [ Take away delivery ] - Here's the takeout !
00:00:02.284 c.TestCorrectPosture [ Little girl ] - Did the takeout arrive ?[true]
00:00:02.284 c.TestCorrectPosture [ Little girl ] - You can start working
00:00:02.284 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
00:00:02.284 c.TestCorrectPosture [ Xiaonan ] - Didn't do it …
explain
Let's take this time notify Instead of notifyAll, So that the little girl must be awakened And receive takeout . And so it is , The little girl got takeout And start working , But Xiao Nan was still awakened And did not receive smoke As a result, Xiao Nan didn't work .
Now the situation is Although I woke up what I should wake up Little female thread , But Xiaonan thread was awakened by the error , Is still spurious wakeup
Simulation five
@Slf4j(topic = "c.TestCorrectPosture")
public class TestCorrectPostureStep5 {
static final Object room = new Object();
static boolean hasCigarette = false;
static boolean hasTakeout = false;
public static void main(String[] args) {
new Thread(() -> {
synchronized (room) {
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
while (!hasCigarette) {
log.debug(" No smoke , Take a break !");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Do you have any cigarettes ?[{}]", hasCigarette);
if (hasCigarette) {
log.debug(" You can start working ");
} else {
log.debug(" Didn't do it ...");
}
}
}, " Xiaonan ").start();
new Thread(() -> {
synchronized (room) {
Thread thread = Thread.currentThread();
log.debug(" Did the takeout arrive ?[{}]", hasTakeout);
while (!hasTakeout) {
log.debug(" No takeout , Take a break !");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(" Did the takeout arrive ?[{}]", hasTakeout);
if (hasTakeout) {
log.debug(" You can start working ");
} else {
log.debug(" Didn't do it ...");
}
}
}, " Little girl ").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
synchronized (room) {
hasTakeout = true;
log.debug(" Here's the takeout !");
room.notifyAll();
}
}, " Take away delivery ").start();
}
}
result
00:10:36.991 c.TestCorrectPosture [ Xiaonan ] - Do you have any cigarettes ?[false]
00:10:36.991 c.TestCorrectPosture [ Xiaonan ] - No smoke , Take a break !
00:10:36.991 c.TestCorrectPosture [ Little girl ] - Did the takeout arrive ?[false]
00:10:36.991 c.TestCorrectPosture [ Little girl ] - No takeout , Take a break !
00:10:37.990 c.TestCorrectPosture [ Take away delivery ] - Here's the takeout !
00:10:37.990 c.TestCorrectPosture [ Little girl ] - Did the takeout arrive ?[true]
00:10:37.990 c.TestCorrectPosture [ Little girl ] - You can start working
00:10:37.990 c.TestCorrectPosture [ Xiaonan ] - No smoke , Take a break !
explain
Here we use a very clever treatment Solved the simulation of four situations in which Xiao Nan was falsely awakened , Here we put Xiaonan's if Judgment to while, If the judgment fails Will cycle again perform wait Get into WaitSet
06.wait/notify Recommended format
synchronized(lock){
while( Conditions not established ){
lock.wait();
}
// Subsequent code
}
// Another thread
synchronized(lock){
lock.notifyAll();
}
This way of writing avoids False awakening It also guarantees The awakened thread must be able to obtain the required conditions So as to work .
边栏推荐
- "Could not load host key" error when xshell connects to the server
- 【4.9 容斥原理详解】
- Downloading and processing of sentinel-2
- Blue Bridge Cup 1004 [recursive] cow story
- 【4.10 博弈论详解】
- [2. TMUX operation]
- Collection of 3D LUT related articles
- When the label begins with "IMS", why does logcat not print the log?
- [acwing game 61]
- 【4.6 中国剩余定理详解】
猜你喜欢

Visual studio C cs0006 C failed to find metadata file

2022-07-17:1, 2, 3... N-1, N, n+1, n+2... In this sequence, only one number has repetition (n). This sequence is unordered. Find the repeated number n. This sequence is ordered. Find the repeated numb

5_线性回归(Linear Regression)

Matlab simulation of image reconstruction using filtered back projection method

Signal and system impulse response and step response

Huffman encoding and decoding

Downloading and processing of sentinel-2

Signal and system learning zero input response

CSDN article syntax rules

Course notes of Professor Dalin of robotics platform
随机推荐
V-viewer use
[Qt]容器类、迭代器、foreach关键字
A simple prime number program. Beginners hope that older bosses can have a look
Blue Bridge Cup 1004 [recursive] cow story
8_多项式回归及模型泛化(Polynomial Regression and Model Generalization)
"Syntaxerror: future feature annotations is not defined"
[Qt]解决中文乱码问题
[qt] meta object system
Mysql互不关联的联表查询(减少了查询的次数)
Eight queens n Queens
Fourier analysis (basic introduction)
9_逻辑回归(Logistic Regression)
[LeetCode] 无重复最长字符串
3_Jupyter Notebook, numpy和matplotlib
13_集成学习和随机森林(Ensemble Learning and Random Forests)
torch.相关函数
2020-12-22最大公因数
Operator overloading
【4.4 快速幂详解及快速幂求逆元】
关于Redis问题的二三事