False wake-up problem caused by wait-notify

wait() notify is often used in application scenarios where the program hangs when a certain condition is not met and then wakes up after it is met.
The problem of false wake-up is: a program exceeds the judgment condition and is illegally executed to produce unexpected execution results.
Let’s look at a scenario of buying and selling goods:

package com.songtao.concurrencycoding.wait;
public class WaitDemo {
    
    
    /**
     * 商品资源类
     */
    static class  ItemResource{
    
    
        private int num;
        private static final int MAX = 10;
        /**
         * 添加商品
         * */
        public synchronized void put() throws InterruptedException {
    
    
            if(num >= MAX){
    
    
//            while (num >= MAX){
    
    
                //doSomething
                System.out.println("商品到达最大库存");
                this.wait();//挂起
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"当前商品剩余"+num);
            this.notifyAll();
        }
        /**
         *  售卖商品
         * */
        public synchronized void sell() throws InterruptedException {
    
    
            if(num <= 0){
    
    
//            while (num <= 0){
    
    
                //doSomething
                System.out.println("商品已经全部售出,等待商品添加");
                this.wait();
            }
            num--;
            System.out.println(Thread.currentThread().getName()+"当前商品剩余"+num);
            this.notifyAll();
        }
    }
    public static void main(String[] args){
    
    
        ItemResource items = new ItemResource();
        new Thread(()->{
    
    
            for(int i=0;i<20;i++){
    
    
                try {
    
    
                    Thread.sleep(100);
                    items.put();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"A生产者").start();
        new Thread(()->{
    
    
            for (int i=0;i<10;i++){
    
    
                try {
    
    
                    Thread.sleep(100);
                    items.sell();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"B1消费者").start();
        new Thread(()->{
    
    
            for (int i=0;i<10;i++){
    
    
                try {
    
    
                    Thread.sleep(100);
                    items.sell();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"B2消费者").start();
    }
}

Results of the:

商品已经全部售出,等待商品添加
商品已经全部售出,等待商品添加
A生产者当前商品剩余1
B1消费者当前商品剩余0
B2消费者当前商品剩余-1
商品已经全部售出,等待商品添加
A生产者当前商品剩余0
B2消费者当前商品剩余-1
商品已经全部售出,等待商品添加
商品已经全部售出,等待商品添加
A生产者当前商品剩余0
B2消费者当前商品剩余-1
B1消费者当前商品剩余-2
A生产者当前商品剩余-1
商品已经全部售出,等待商品添加
商品已经全部售出,等待商品添加
A生产者当前商品剩余0
B1消费者当前商品剩余-1
B2消费者当前商品剩余-2
商品已经全部售出,等待商品添加
商品已经全部售出,等待商品添加
A生产者当前商品剩余-1
B2消费者当前商品剩余-2
B1消费者当前商品剩余-3
商品已经全部售出,等待商品添加
A生产者当前商品剩余-2
B1消费者当前商品剩余-3
商品已经全部售出,等待商品添加
A生产者当前商品剩余-2
B2消费者当前商品剩余-3
商品已经全部售出,等待商品添加
商品已经全部售出,等待商品添加
A生产者当前商品剩余-2
B2消费者当前商品剩余-3
B1消费者当前商品剩余-4
A生产者当前商品剩余-3
商品已经全部售出,等待商品添加
商品已经全部售出,等待商品添加

In this scenario, when we execute multiple consumers, the problem of false wake-up will occur. This is because when the producer produces the goods, it will wake up all waiting threads, but because the previously suspended program is hanging When it is woken up, it will not judge the quantity of the product @code if(num <= 0), so that after consumption by another thread, it is obvious that the quantity of the product is 0 , but the awakened thread is "resurrected" from the original place , and then Consumption.
Solution: The awakened thread needs to judge the quantity of the product again to verify the legality of the execution. Just replace the if judgment with a loop judgment. if(num >= 0) ->while(num >= 0)
Conclusion: wait must be placed in a conditional judgment loop to prevent false wake-up problems.
operation result:
Insert image description here

Guess you like

Origin blog.csdn.net/qq_52605986/article/details/132421715