Java-JUC (8): Use wait, notify|notifyAll to complete producer-consumer communication, scenarios of spurious wakeups, and problem solutions.

Simulate implementing the consumer and subscriber patterns via threads:

First, define a clerk: the clerk includes the methods of purchasing and selling goods; secondly, define a producer, and the producer is responsible for producing products for the clerk; third, define a consumer, and the consumer is responsible for consuming products from the clerk.

Clerk:

/**
 * shop assistant
 */
class Clerk {
    private int product = 0;

    /**
     * Restocking
     */
    public synchronized void purchase() {
        if (product >= 10) {
            System.out.println( "Product is full..." );
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + ++product);
        }
    }

    /**
     * for sale
     */
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println( "The product is out of stock..." );
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + --product);
        }
    }
}

producer

/**
 * Producers continue to produce products for shop assistants
 * */
class Productor implements Runnable{
    private Clerk clerk;
    public Productor(Clerk clerk){
        this.clerk=clerk;
    }
    
    public void run() {
        for(int i=0;i<20;i++){
            clerk.purchase();
        }        
    }
}

consumer

/**
 * Consumers continue to consume products from shop assistants
 * */
class Consumer implements Runnable{
    private Clerk clerk;
    public Consumer(Clerk clerk){
        this.clerk=clerk;
    }
    
    public void run() {
        for(int i=0;i<20;i++){
            clerk.sell();
        }        
    }
}

At this point, run the program and the results are as follows:

Producer-A:1 
Producer -A:2 
Producer -A:3 
Producer -A:4 
Producer -A:5 
Producer -A:6 
Producer -A:7 
Producer -A:8 
Producer -A:9 
Producer -A:10
Product is full. . .
Product is full. . .
Product is full. . .
Product is full. . .
Product is full. . .
Product is full. . .
Product is full. . .
Product is full. . .
Product is full. . .
Product is full. . .
Consumer-A:9
Consumer-A:8
Consumer-A:7
Consumer-A:6
Consumer-A:5
Consumer-A:4
Consumer-A:3
Consumer-A:2
Consumer-A:1
Consumer-A:0
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .
Product is out of stock. . .

From the running print results, it can be found that there are two problems here:

1) Once the producer finds that the clerk's product is full, it still does not stop producing the product, and continues to produce the product;

2) Once consumers find that the clerk's products are out of stock, they will continue to consume and consume.

This is obviously flawed. In reality, it should be: once the goods are found to be full, they will not be stocked, but will start selling; when the seller finds that there is no stock, they will start buying.

Improvements for producer consumers:

The calling code of consumers, producers, and clients remains unchanged, and only the clerk class is modified:

/**
 * shop assistant
 */
class Clerk {
    private int product = 0;

    /**
     * Restocking
     */
    public synchronized void purchase() {
        if (product >= 10) {
            System.out.println( "Product is full..." );
             try {
                 this .wait();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + ++product);
            this.notifyAll();
        }
    }

    /**
     * for sale
     */
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println( "The product is out of stock..." );
             try {
                 this .wait();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + --product);
            this.notifyAll();
        }
    }
}

Running result at this point:

Producer-A:1 
Consumer -A:0
Product is out of stock. . .
Producer -A:1 
Producer -A:2 
Producer -A:3 
Producer -A:4 
Producer -A:5 
Producer -A:6 
Producer -A:7 
Producer -A:8 
Producer -A:9 
Producer -A:10
Product is full. . .
Consumer-A:9
Consumer-A:8
Consumer-A:7
Consumer-A:6
Consumer-A:5
Consumer-A:4
Consumer-A:3
Consumer-A:2
Consumer-A:1
Consumer-A:0
Product is out of stock. . .
Producer -A:1 
Producer -A:2 
Producer -A:3 
Producer -A:4 
Producer -A:5 
Producer -A:6 
Producer -A:7 
Producer -A:8 
Consumer -A:7 
Consumer -A:6 
Consumer -A:5 
Consumer -A:4 
Consumer -A:3 
Consumer -A:2 
Consumer -A:1

At this point, from the results of the operation, the results appear as we hoped.

Problem one after improvement:

Modify the maximum number of purchases for the clerk class to 1, change the producer's production of 20 to 2, and the consumer's consumption of 20 to 2.

Shop assistant class:

/**
 * shop assistant
 */
class Clerk {
    private int product = 0;

    /**
     * Restocking
     */
    public synchronized void purchase() {
        if (product >= 1) {
            System.out.println( "Product is full..." );
             try {
                 this .wait();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + ++product);
            this.notifyAll();
        }
    }

    /**
     * for sale
     */
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println( "The product is out of stock..." );
             try {
                 this .wait();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + --product);
            this.notifyAll();
        }
    }
}

Running result at this point:

From the running results, the program is a deadlock phenomenon.

Why does the deadlock problem occur?

Analysis from the running results:

 

 

Problem two after improvement:

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324854984&siteId=291194637