Waiting awakening mechanism
1.1 Interthread Communication
Concept: Multiple threads are dealing with the same resource, but their actions (thread tasks) are different, so there are communication problems between multiple threads.
For example, thread A is used to produce steamed buns, thread B is used to eat steamed buns, steamed buns can be understood as the same resource, thread A and thread B processing actions, one is production, one is consumption, then there is thread communication problem between thread A and thread B.
Why do you deal with inter-thread communication?
By default, the scheduling of threads is preemptive. When we need multiple threads to complete a task, and we want them to execute regularly, we need some coordinated communication between threads to achieve multi-threads to operate the same data together.
How to ensure the effective use of resources for inter-thread communication?
When multiple threads are dealing with the same resource and tasks are different, communication between threads is needed to help resolve the use or operation of the same variable among threads. When multiple threads operate on the same data, they avoid competing for the same shared variable. That is to say, we need to make effective use of resources among threads by some means. And this means is waiting for wake-up mechanism.
1.2 Waiting awakening mechanism
What is the awakening mechanism?
This is a collaboration mechanism between multiple threads. After a thread has performed a specified operation, it enters a waiting state (wait()) and waits for other threads to execute their specified code before waking up (notify (). When there are multiple threads waiting, if necessary, notify all () can be used to wake up all waiting threads.
wait/notify is a collaboration mechanism between threads.
Ways to Wait for Wake-up
Waiting for wake-up mechanism is used to solve the problem of inter-thread communication. The meaning of the three methods used is as follows:
- wait(): Threads are not active, no longer participate in scheduling, enter the wait set, the voice fool will not let cpu resources, nor will it compete for locks, when the thread state is waiting. It also performs a special action, that is, "notify" on the object waiting for the thread released from the wait set, re-enter to In the ready queue.
- Notfy: Select a thread in the wait set of the notified object to release; for example, when the restaurant is free, the customer who waits for the longest meal is the first to be seated.
- NotfyAll: Releases all threads on the wait set of the notified object.
Details to note when calling wait and notify methods
- The wait method and the notify method must be invoked by the same lock object. Because: the corresponding lock object can wake up the thread using the wait method called by the same lock object through notify.
- The wait method and notify method belong to the Object class. Because: the lock object can be any object, and the class of any object is inherited from the Object class.
- The wait method and the notify method must be used in the synchronization block or the synchronization function. Because: these two methods must be invoked through the lock object.
1.3 Effective communication case between two threads
- producer consumer problem
Take steamed bun shops and consumers for example:
The steamed bun shop thread produces steamed buns, and the eating thread consumes steamed buns. When the steamed bun is not available (the state of the steamed bun is false), the feeding thread waits, the steamed bun shop thread produces the steamed bun (that is, the state of the steamed bun is true), and notifies the feeding thread (to remove the waiting state of the steamed bun), because there are already steamed buns, then the steamed bun shop thread enters the waiting state. Next, whether the feeding thread can execute further depends on the acquisition of the lock. If the lock is acquired, the action of eating steamed buns is executed. When the steamed buns are finished (the state of steamed buns is false), the thread of steamed buns shop is notified (the waiting state of steamed buns shop is released), and the thread of eating steamed buns enters the waiting state. Whether the bun-laying thread can be further executed depends on the acquisition of locks.
Code demonstration:
Baozi resources:
public class BaoZi { String pier ; String xianer ; boolean flag = false ;//Is there a status of Baozi resource in Baozi resource? }
Eating Thread Class:
public class ChiHuo extends Thread{ private BaoZi bz; public ChiHuo(String name,BaoZi bz){ super(name); this.bz = bz; } @Override public void run() { while(true){ synchronized (bz){ if(bz.flag == false){//No steamed buns try { bz.wait(500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Eating is eating"+bz.pier+bz.xianer+"Steamed stuffed bun"); bz.flag = false; bz.notify(); } } } }
Pack Thread Class:
public class BaoZiPu extends Thread { private BaoZi bz; public BaoZiPu(String name,BaoZi bz){ super(name); this.bz = bz; } @Override public void run() { int count = 0; //Making steamed buns while(true){ //synchronization synchronized (bz){ if(bz.flag == true){//The existence of Baozi resources try { bz.wait(500); } catch (InterruptedException e) { e.printStackTrace(); } } // No steamed buns to make steamed buns System.out.println("The steamed bun shop began to make steamed buns."); if(count%2 == 0){ // Three Fresh Faces bz.pier = "Face"; bz.xianer = "three delicacies"; }else{ // Thin-skinned beef bz.pier = "Thin skin"; bz.xianer = "beef"; } count++; bz.flag=true; System.out.println("The steamed bun is made."+bz.pier+bz.xianer); System.out.println("Let's eat."); //Wake up waiting threads (eat) bz.notify(); } } } }
Test class:
public class Demo { public static void main(String[] args) { //Waiting for wake-up cases BaoZi bz = new BaoZi(); ChiHuo ch = new ChiHuo("Foodie",bz); BaoZiPu bzp = new BaoZiPu("Steamed bun shop",bz); ch.start(); bzp.start(); } }
Implementation effect:
The steamed bun shop began to make steamed buns. Steamed buns: three fresh skins Let's eat. Food is eating noodles and steamed buns The steamed bun shop began to make steamed buns. Steamed buns: thin-skinned beef Let's eat. Eating Thin-skinned Beef Steamed buns The steamed bun shop began to make steamed buns. Steamed buns: three fresh skins Let's eat. Food is eating noodles and steamed buns
1.4 Effective communication between threads
If multiple threads want to achieve synchronization, multiple threads must add the same lock - > to achieve thread safety Implementing effective communication: letting threads A, B and C execute alternately If thread A is executing, then the BC thread can only enter the wireless waiting, and then when thread A is finished, it has to wake up all waiting threads. If the B thread is executed, then the AC thread can only enter the wireless wait, and then the B thread has to wake up all the waiting threads when the B thread is executed. If the C thread is executing, then the AB thread can only enter the wireless wait, and then when the C thread is finished, it has to wake up all waiting threads. If thread A finishes executing, then thread B must grab it, even if AC grabs it, it has to wait infinitely. After B is executed, wake up all threads and let C thread grab it. Even if AB grabs it, it has to wait infinitely. After C executes, wake up all threads, must let A thread grab, even BC grab also must enter infinite wait. After thread A is executed, thread B must be grabbed, even if AC is grabbed, it has to wait infinitely. .....
Bricks:
public class Zhuan { int num ; }
Brickyard:
public class ZhuanCang implements Runnable{ Zhuan z; public ZhuanCang(Zhuan z) { this.z = z; } @Override public void run() { while (true) { synchronized (z) { while (z.num % 3 != 0) {//So instead of using the while statement, when awakened, if the lock is snatched, it will still be judged. //If (z. num% 3!= 1) {If the if structure is used, when the thread is waked up, it is executed directly backwards, which can not achieve the desired effect. try { z.wait(); } catch (InterruptedException e) { e.printStackTrace(); } // } } System.out.println("In brickmaking"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Bricks have been made.,Brickmen come and move"); z.num++; z.notifyAll(); } } } }
Brick movers:
public class BanZhuanGong implements Runnable{ Zhuan z; public BanZhuanGong(Zhuan z) { this.z = z; } @Override public void run() { while (true) { synchronized (z){ while (z.num % 3 != 1) {//So instead of using the while statement, when awakened, if the lock is snatched, it will still be judged. //If (z. num% 3!= 1) {If the if structure is used, when the thread is waked up, it is executed directly backwards, which can not achieve the desired effect. try { z.wait(); } catch (InterruptedException e) { e.printStackTrace(); } // } } z.notifyAll(); System.out.println("Moving bricks,Moving bricks,Moving bricks"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("The bricks have been removed.,rest"); z.num++; } } } }
Architect:
public class JianZuShi implements Runnable { Zhuan z; public JianZuShi(Zhuan z) { this.z = z; } @Override public void run() { while (true) { synchronized (z) { while (z.num % 3 != 2){//So instead of using the while statement, when awakened, if the lock is snatched, it will still be judged. //If (z. num% 3!= 1) {If the if structure is used, when the thread is waked up, it is executed directly backwards, which can not achieve the desired effect. try { z.wait(); } catch (InterruptedException e) { e.printStackTrace(); } // } } System.out.println("Building a house"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("No bricks,rest,Wait till the bricklayers move the bricks"); z.num++; z.notifyAll(); } } } }
Test class:
public class Test { public static void main(String[] args) { Zhuan z = new Zhuan(); ZhuanCang zc = new ZhuanCang(z); BanZhuanGong bzg = new BanZhuanGong(z); JianZuShi jzs = new JianZuShi(z); Thread t1 = new Thread(zc); Thread t2 = new Thread(bzg); Thread t3 = new Thread(jzs); t1.start(); t2.start(); t3.start(); } }
Operation results:
In brickmaking Bricks are ready. Brickmen are coming to move them. Brick removal, brick removal, brick removal When the bricks have been moved, take a rest. Building a house No bricks, rest, wait tiller to move bricks In brickmaking Bricks are ready. Brickmen are coming to move them. Brick removal, brick removal, brick removal When the bricks have been moved, take a rest. Building a house No bricks, rest, wait tiller to move bricks
Summary:
1. The lock objects calling wait() and notfiy() and notifyAll() methods should be consistent
2. Thread scheduling is preemptive scheduling
3. When a thread enters an infinite wait, it will not preempt lock objects and cpu resources.
4. If a thread is awakened from an infinite waiting state, it will continue to execute from an infinite waiting position when the lock object is grabbed.