Author: forget the clearance link: www.jianshu.com/p/91d95bb5a…
Perhaps we only know that wait and notify implement thread communication and use synchronized encapsulation, but this is not enough in development. Let’s look at two common questions.
Problem 1: Notification loss
Create two threads, one for calculation and one for obtaining results.
public class Calculator extends Thread {
int total;
@Override
public void run(a) {
synchronized (this) {for(int i = 0; i < 101; i++){
total += i;
}
this.notify(); }}}public class ReaderResult extends Thread {
Calculator c;
public ReaderResult(Calculator c) {
this.c = c;
}
@Override
public void run(a) {
synchronized (c) {
try {
System.out.println(Thread.currentThread() + "Waiting for the calculation junction...");
c.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "The calculated result is :"+ c.total); }}public static void main(String[] args) {
Calculator calculator = new Calculator();
// Start the thread to get the results
newReaderResult(calculator).start(); calculator.start(); }}Copy the code
We get the desired results:
Thread[thread-1,5,main]... Thread[thread-1,5,main] :5050Copy the code
But what if we change it to start the computational thread first?
calculator.start();
new ReaderResult(calculator).start();
Copy the code
This is where the thread has been waiting to get the settlement result:
Thread[thread-1,5,main]...Copy the code
Problem analysis
Print out the thread stack:
"Thread-1" prio=5 tid=0x00007f983b87e000 nid=0x4d03 in Object.wait() [0x0000000118988000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007d56fb4d0> (a com.concurrent.waitnotify.Calculator)
at java.lang.Object.wait(Object.java:503)
at com.concurrent.waitnotify.ReaderResult.run(ReaderResult.java:18)
- locked <0x00000007d56fb4d0> (a com.concurrent.waitnotify.Calculator)
Copy the code
You can see that the ReaderResult is waiting on Calculator. Happen this phenomenon is often said that the notice is missing, before get notice, notify in advance, we first calculated results, calculate again after the notice, but this time to get the results without waiting for the notice, wait for the results of the thread to get the results, this notice has been notified, so lost, then how can we avoid? You can set a variable to indicate whether it has been notified or not, with the following code:
public class Calculator extends Thread {
int total;
boolean isSignalled = false;
@Override
public void run(a) {
synchronized (this) {
isSignalled = true;// It has been notified
for (int i = 0; i < 101; i++) {
total += i;
}
this.notify(); }}}public class ReaderResult extends Thread {
Calculator c;
public ReaderResult(Calculator c) {
this.c = c;
}
@Override
public void run(a) {
synchronized (c) {
if(! c.isSignalled) {// Determine if you have been notified
try {
System.out.println(Thread.currentThread() + "Waiting for the calculation junction...");
c.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "The calculated result is :"+ c.total); }}}public static void main(String[] args) {
Calculator calculator = new Calculator();
newReaderResult(calculator).start(); calculator.start(); }}Copy the code
Problem two: false awakening
Two threads remove elements from the array, wait until there are none, and another thread adds an element, notifying the deletion thread.
public class EarlyNotify{
private List list;
public EarlyNotify(a) {
list = Collections.synchronizedList(new LinkedList());
}
public String removeItem(a) throws InterruptedException {
synchronized ( list ) {
if ( list.isEmpty()) {// That's the problem
list.wait(a); }// Delete elements
String item = (String) list.remove(0);
returnitem; }}public void addItem(String item) {
synchronized ( list ) {
// Add elements
list.add(item);
// Notify all threads when added
list.notifyAll();
}
}
private static void print(String msg) {
String name = Thread.currentThread().getName(a); System.out.println(name + ":" + msg);
}
public static void main(String[] args) {
final EarlyNotify en = new EarlyNotify(a); Runnable runA =new Runnable() {
public void run() {
try {
String item = en.removeItem(a); }catch ( InterruptedException ix ) {
print("interrupted!");
} catch ( Exception x ) {
print("threw an Exception!!! \n"+ x); }}}; Runnable runB =new Runnable() {
public void run() {
en.addItem("Hello!"); }};try {
// Start the first thread to remove the element
Thread threadA1 = new Thread(runA, "threadA1");
threadA1.start(a); Thread.sleep(500);
// Start the second thread to delete the element
Thread threadA2 = new Thread(runA, "threadA2");
threadA2.start(a); Thread.sleep(500);
// Start the thread to add elements
Thread threadB = new Thread(runB, "threadB");
threadB.start(a); Thread.sleep(1000); // wait 10 seconds
threadA1.interrupt(a); threadA2.interrupt(a); }catch ( InterruptedException x ) {}
}
}
Copy the code
Results:
threadA1: threw an Exception!!!
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
Copy the code
There’s a false wake up, when you add an element and wake up two threads to delete it, there’s only one element, so it throws an array out of bounds, and then we need to wake up to see if there are any more elements.
Modify code:
public String removeItem(a) throws InterruptedException {
synchronized ( list ) {
while ( list.isEmpty()) {// That's the problem
list.wait(a); }// Delete elements
String item = (String) list.remove(0);
returnitem; }}Copy the code
Typical wait/notification paradigm
From the above questions we can generalize the typical wait/notification paradigm.
The paradigm is divided into two parts, one for the waiting party (consumer) and the other for the notifying party (producer).
The waiting party follows the following principles:
- Gets the lock of the object
- If the condition is not met, the object’s wait() method is called and the condition is still checked after being notified
- If the conditions are met, the corresponding logic is executed
Corresponding pseudocodes are as follows:
Synchronized (objects) {while(Condition not met){object.wait(a); } Corresponding processing logic}Copy the code
The notifying party follows the following principles:
- Get the lock of the object
- Change the conditions
- Notify the thread waiting on the object
Corresponding pseudocodes are as follows:
synchronized(object){change the condition object. NotifyAll (); }Copy the code
Recent hot articles recommended:
1.1,000+ Java Interview Questions and Answers (2021)
2. I finally got the IntelliJ IDEA activation code thanks to the open source project. How sweet!
3. Ali Mock is officially open source, killing all Mock tools on the market!
4.Spring Cloud 2020.0.0 is officially released, a new and disruptive version!
5. “Java Development Manual (Songshan version)” the latest release, quick download!
Feel good, don’t forget to click on + forward oh!