1 false Awakening
What is false awakening?
Refer to a question and answer on the Internet:
Question: what are the reasons for false wakeup in java multithreading?
The definition found on the Internet means that the thread wakes up without calling notify() and notifyAll(), which is a false wake-up. What causes this?
Answer: spurious wakeup is an appearance, that is, in a multiprocessor system, the program that sends a wait may wake up and continue to execute without notify wakeup. Taking the java program running on the linux hotspot virtual machine as an example, the wait method essentially calls the underlying pthread when the jvm executes_ cond_ wait/pthread_ cond_ The timedwait function suspends the wait condition variable to achieve the effect of synchronous communication between threads. At the beginning of design, in order not to slow down the efficiency of condition variable operation, the underlying wait function did not guarantee that each wake-up was triggered by notify, but entrusted this task to the upper application, That is, the user needs to define a loop to judge whether the conditions can really meet the needs of the program to continue running. Of course, this implementation can also avoid the problem of abnormal wake-up of the program due to design defects.
Let's reproduce the scene
class ProConShop{ int num; /** * The clerk put the goods on the shelf */ public synchronized void incrementProduct() throws InterruptedException { //1. Judge whether there are goods in the store if (num!=0){//spurious wakeup //while (num!=0){ this.wait(); } //2 production goods num++; System.out.println(Thread.currentThread().getName()+"Put in the item with the item No"+num); //3 notify consumers this.notifyAll(); } /** * Consumer goods */ public synchronized void decrementProduct() throws InterruptedException { //1. Judge whether there are goods in the store if (num==0){ //while (num==0){ this.wait(); } //2 consumer goods System.out.println(Thread.currentThread().getName()+"Customer No. purchased commodity, commodity No"+num); num--; //3 notify the producer this.notifyAll(); } } public class ProductTest { public static void main(String[] args) { ProConShop shop = new ProConShop(); for (int i = 1; i <= 5; i++) { new Thread(()->{ try { shop.incrementProduct(); } catch (InterruptedException e) { e.printStackTrace(); } },"clerk").start(); } for (int i = 1; i <= 5; i++) { new Thread(()->{ try { shop.decrementProduct(); } catch (InterruptedException e) { e.printStackTrace(); } },i+"").start(); } } }
From this place num= 0 thread has no wait
This article 00 multithreading 5.2 thread communication case: the producer consumer code has a false wake-up problem
An interpretation from the Internet
Solution: replace the producer consumer method judgment statement if with while
The operation effect is:
2 producer consumer case Lock mode
Producer consumer case synchronized implementation 1 false Awakening
2.1 use lock instead of synchronized
Lock lock = new ReentrantLock(); Condition condition = lock.newCondition();
package com.nie.juc; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class ProConShop{ int num = 0; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); /** * The clerk put the goods on the shelf */ public void incrementProduct() throws InterruptedException { lock.lock(); try { //1. Judge whether there are goods in the store while (num!=0){ this.wait(); // condition.await();// wait for } //2 production goods num++; System.out.println(Thread.currentThread().getName()+"Put in the item with the item No"+num); //3 notify consumers this.notifyAll(); // condition.signalAll();// awaken }finally { lock.unlock();//Release lock } } /** * Consumer goods */ public void decrementProduct() throws InterruptedException { lock.lock(); try { //1. Judge whether there are goods in the store while (num==0){ this.wait(); // condition.await();// wait for } //2 consumer goods System.out.println(Thread.currentThread().getName()+"Customer No. purchased commodity, commodity No"+num); num--; //3 notify the producer this.notifyAll(); // condition.signalAll();// awaken }finally { lock.unlock();//Release lock } } } public class ProductTest { public static void main(String[] args) { ProConShop shop = new ProConShop(); for (int i = 1; i <= 5; i++) { new Thread(()->{ try { shop.incrementProduct(); } catch (InterruptedException e) { e.printStackTrace(); } },"Clerk 1").start(); } for (int i = 1; i <= 5; i++) { new Thread(()->{ try { shop.decrementProduct(); } catch (InterruptedException e) { e.printStackTrace(); } },"First customers"+i).start(); } } }
Run code error
The solution is to replace the previous wait() and notifyAll() with wait wait() and wake signalAll() of Condition
2.2 precise notification sequence access
The advantage of using lock.Condition is that it can accurately wake up the threads you want to execute
For example: ① multiple threads are called in order to realize a - > b - > C ② traffic light scenario
Traffic light scene simulation code
package com.nie.juc; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Simulated traffic lights */ class TrafficLight{ Lock lock = new ReentrantLock(); Condition green = lock.newCondition();//green light Condition yellow = lock.newCondition();//Yellow lamp Condition red = lock.newCondition();//red light //1-green 2-yellow 3-red volatile int state = 1; public void greenLight(){ lock.lock(); try { if (state!=1){ //Judge whether the light is green. If not, wait green.await(); } else { System.out.println(Thread.currentThread().getName()+"\t pass at a green light========="); TimeUnit.SECONDS.sleep(1); //Notification yellow light state=2; yellow.signal(); // green.signalAll(); // it won 't work } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void yellowLight(){ lock.lock(); try { if (state!=2){ //Judge whether it is yellow. If not, wait yellow.await(); }else { System.out.println(Thread.currentThread().getName()+"\t Yellow light, wait a minute========="); TimeUnit.SECONDS.sleep(1); //Notification red light state=3; red.signal(); // yellow.signalAll(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void redLight(){ lock.lock(); try { if (state!=3){ //Judge whether it is a red light. If not, wait red.await(); }else { System.out.println(Thread.currentThread().getName()+"\t Stop at red light========="); TimeUnit.SECONDS.sleep(1); //Notification green light state=1; green.signal(); // red.signalAll(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public class TrafficLightDemo { public static void main(String[] args) { TrafficLight trafficLight = new TrafficLight(); new Thread(()->{ while (true) { trafficLight.greenLight(); } }).start(); new Thread(()->{ while (true) { trafficLight.yellowLight(); } }).start(); new Thread(()->{ while (true) { trafficLight.redLight(); } }).start(); } }
The print result is: