欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

生产者消费者问题虚假唤醒

程序员文章站 2022-07-13 14:50:27
...

生产者消费者问题演示及解决

问题一:

package com.mock;

import org.junit.jupiter.api.Test;

public class TestProducerAndConsumer {
    @Test
    public void test() {
        Product p = new Product();
        new Thread(new Producer(p), "生产者1").start();
        new Thread(new Consumer(p), "消费者1").start();
    }
}

class Producer implements Runnable {
    private Product product;

    public Producer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            product.produce();
        }
    }
}

class Consumer implements Runnable {

    private Product product;

    public Consumer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            product.consume();
        }
    }
}

/**
 * 货物
 */
class Product {
    private int total = 0;

    public synchronized void produce() {
        if (total >= 6) {
            System.out.println("货物已满");
        } else {
            System.out.println(Thread.currentThread().getName() + "---" + ++total);
        }
    }

    public synchronized void consume() {
        if (total <= 0) {
            System.out.println("缺货中....");
        } else {
            System.out.println(Thread.currentThread().getName() + "---" + --total);
        }
    }
}
生产者1---1
生产者1---2
生产者1---3
生产者1---4
生产者1---5
生产者1---6
货物已满
货物已满
货物已满
货物已满
消费者1---5
消费者1---4
消费者1---3
消费者1---2
消费者1---1
消费者1---0
缺货中....
缺货中....
缺货中....
缺货中....

会出现数据丢失或者数据重复读的问题

解决方法,使用等待唤醒机制(wait() notifyAll())

package com.mock;

import org.junit.jupiter.api.Test;

public class TestProducerAndConsumer {
    @Test
    public void test() {
        Product p = new Product();
        new Thread(new Producer(p), "生产者1").start();
        new Thread(new Consumer(p), "消费者1").start();
    }
}

class Producer implements Runnable {
    private Product product;

    public Producer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            product.produce();
        }
    }
}

class Consumer implements Runnable {

    private Product product;

    public Consumer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            product.consume();
        }
    }
}

/**
 * 货物
 */
class Product {
    private int total = 0;

    public synchronized void produce() {
        if (total >= 6) {
            System.out.println("货物已满");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "---" + ++total);
            this.notifyAll();
        }
    }

    public synchronized void consume() {
        if (total <= 0) {
            System.out.println("缺货中....");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "---" + --total);
            this.notifyAll();
        }
    }
}
生产者1---1
生产者1---2
生产者1---3
生产者1---4
生产者1---5
生产者1---6
货物已满
消费者1---5
消费者1---4
消费者1---3
消费者1---2
消费者1---1
消费者1---0
缺货中....
生产者1---1
生产者1---2
生产者1---3
消费者1---2
消费者1---1
消费者1---0

问题二

package com.mock;

public class TestProducerAndConsumer {

    public static void main(String[] args) {
        Product p = new Product();
        new Thread(new Producer(p), "生产者1").start();
        new Thread(new Consumer(p), "消费者1").start();
    }
}

class Producer implements Runnable {
    private Product product;

    public Producer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                product.produce();
                Thread.sleep(222);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {

    private Product product;

    public Consumer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            product.consume();
        }
    }
}

/**
 * 货物
 */
class Product {
    private int total = 0;

    public synchronized void produce() {
        if (total >= 1) {
            System.out.println("货物已满");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "---" + ++total);
            this.notifyAll();
        }
    }

    public synchronized void consume() {
        if (total <= 0) {
            System.out.println("缺货中....");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "---" + --total);
            this.notifyAll();
        }
    }
}

生产者消费者问题虚假唤醒

程序并没有停下来
问题分析:生产者生产有延迟,所以消费者循环的快,消费者先结束循环(有一次货物没有消费,没法唤醒等待着的生产者),生产者最后一次循环时进入货物已满逻辑进行等待,所以程序没有结束。

解决方法(去掉else)

package com.mock;

public class TestProducerAndConsumer {

    public static void main(String[] args) {
        Product p = new Product();
        new Thread(new Producer(p), "生产者1").start();
        new Thread(new Consumer(p), "消费者1").start();
    }
}

class Producer implements Runnable {
    private Product product;

    public Producer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                product.produce();
                Thread.sleep(222);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {

    private Product product;

    public Consumer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            product.consume();
        }
    }
}

/**
 * 货物
 */
class Product {
    private int total = 0;

    public synchronized void produce() {
        if (total >= 1) {
            System.out.println("货物已满");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        System.out.println(Thread.currentThread().getName() + "---" + ++total);
        this.notifyAll();
    }

    public synchronized void consume() {
        if (total <= 0) {
            System.out.println("缺货中....");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "---" + --total);
        this.notifyAll();
    }
}

问题三(多个生产消费者)虚假唤醒

package com.mock;

public class TestProducerAndConsumer {

    public static void main(String[] args) {
        Product p = new Product();
        new Thread(new Producer(p), "生产者1").start();
        new Thread(new Consumer(p), "消费者1").start();
        new Thread(new Producer(p), "生产者2").start();
        new Thread(new Consumer(p), "消费者2").start();
    }
}

class Producer implements Runnable {
    private Product product;

    public Producer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                product.produce();
                Thread.sleep(222);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {

    private Product product;

    public Consumer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            product.consume();
        }
    }
}

/**
 * 货物
 */
class Product {
    private int total = 0;

    public synchronized void produce() {
        if (total >= 1) {
            System.out.println("货物已满");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        System.out.println(Thread.currentThread().getName() + "##" + ++total);
        this.notifyAll();
    }

    public synchronized void consume() {
        if (total <= 0) {
            System.out.println("缺货中....");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "##" + --total);
        this.notifyAll();
    }
}
缺货中....
消费者1##-25
缺货中....
消费者2##-26
缺货中....
消费者1##-27
缺货中....
消费者2##-28
缺货中....
消费者1##-29
缺货中....
消费者2##-30
缺货中....
消费者1##-31
缺货中....
消费者2##-32
缺货中....
消费者1##-33
消费者2##-34
缺货中....
生产者1##-33
消费者2##-34

生产者消费者问题虚假唤醒

问题分析:两个消费者进入consume()方法消费,发现没有货物同时等待,生产者生产后唤醒消费者,两个消费者同时消费,会出现负数。

问题解决

需要循环判断,避免虚假唤醒

package com.mock;

public class TestProducerAndConsumer {

    public static void main(String[] args) {
        Product p = new Product();
        new Thread(new Producer(p), "生产者1").start();
        new Thread(new Consumer(p), "消费者1").start();
        new Thread(new Producer(p), "生产者2").start();
        new Thread(new Consumer(p), "消费者2").start();
    }
}

class Producer implements Runnable {
    private Product product;

    public Producer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                product.produce();
                Thread.sleep(222);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {

    private Product product;

    public Consumer(Product product) {
        this.product = product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            product.consume();
        }
    }
}

/**
 * 货物
 */
class Product {
    private int total = 0;

    public synchronized void produce() {
        while (total >= 1) {
            System.out.println("货物已满");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        System.out.println(Thread.currentThread().getName() + "##" + ++total);
        this.notifyAll();
    }

    public synchronized void consume() {
        while (total <= 0) {
            System.out.println("缺货中....");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "##" + --total);
        this.notifyAll();
    }
}
相关标签: JUC