码迷,mamicode.com
首页 > 编程语言 > 详细

Java-JUC(八):使用wait,notify|notifyAll完成生产者消费者通信,虚假唤醒(Spurious Wakeups)问题出现场景,及问题解决方案。

时间:2018-04-25 20:06:41      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:分享   style   col   src   缺陷   生产   ack   public   包含   

模拟通过线程实现消费者和订阅者模式:

首先,定义一个店员:店员包含进货、卖货方法;其次,定义一个生产者,生产者负责给店员生产产品;再者,定义一个消费者,消费者负责从店员那里消费产品。

店员:

/**
 * 店员
 */
class Clerk {
    private int product = 0;

    /**
     * 进货
     */
    public synchronized void purchase() {
        if (product >= 10) {
            System.out.println("产品已满。。。");
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + ++product);
        }
    }

    /**
     * 卖货
     */
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println("产品缺貨。。。");
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + --product);
        }
    }
}

生产者

/**
 * 生产者 不断的生产产品给店员
 * */
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();
        }        
    }
}

消费者

/**
 * 消费者 不断的从店员那里消费产品
 * */
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();
        }        
    }
}

此时,运行程序,运行结果如下:

Productor-A:1
Productor-A:2
Productor-A:3
Productor-A:4
Productor-A:5
Productor-A:6
Productor-A:7
Productor-A:8
Productor-A:9
Productor-A:10
产品已满。。。
产品已满。。。
产品已满。。。
产品已满。。。
产品已满。。。
产品已满。。。
产品已满。。。
产品已满。。。
产品已满。。。
产品已满。。。
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
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。
产品缺貨。。。

从运行打印结果可以发现这里存在两个问题:

1)一旦生产者发现店员产品已满时,仍然没有停止生产产品,在不断地生产生产产品;

2)一旦消费者发现店员产品缺货时,依然时不断地消费消费。

这里明显是有缺陷的,现实中应该是:一旦发现货物满时,就不在进货,而是开启卖货行为;当卖货行为发现无货时,开始进货行为。

针对生产者消费者改进:

消费者、生产者、客户端调用代码不变,只修改店员类:

/**
 * 店员
 */
class Clerk {
    private int product = 0;

    /**
     * 进货
     */
    public synchronized void purchase() {
        if (product >= 10) {
            System.out.println("产品已满。。。");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + ++product);
            this.notifyAll();
        }
    }

    /**
     * 卖货
     */
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println("产品缺貨。。。");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + --product);
            this.notifyAll();
        }
    }
}

此时运行结果:

Productor-A:1
Consumer-A:0
产品缺貨。。。
Productor-A:1
Productor-A:2
Productor-A:3
Productor-A:4
Productor-A:5
Productor-A:6
Productor-A:7
Productor-A:8
Productor-A:9
Productor-A:10
产品已满。。。
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
产品缺貨。。。
Productor-A:1
Productor-A:2
Productor-A:3
Productor-A:4
Productor-A:5
Productor-A:6
Productor-A:7
Productor-A:8
Consumer-A:7
Consumer-A:6
Consumer-A:5
Consumer-A:4
Consumer-A:3
Consumer-A:2
Consumer-A:1

此时,从结果运行来说是按照我们希望的结果出现了。

改进后带来问题一:

修改店员类的最大进货数为1,把生产者一次生产20修改为2,消费者一次消费20也修改为2。

店员类:

/**
 * 店员
 */
class Clerk {
    private int product = 0;

    /**
     * 进货
     */
    public synchronized void purchase() {
        if (product >= 1) {
            System.out.println("产品已满。。。");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + ++product);
            this.notifyAll();
        }
    }

    /**
     * 卖货
     */
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println("产品缺貨。。。");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + ":" + --product);
            this.notifyAll();
        }
    }
}

此时运行结果:

技术分享图片

从运行结果上来看,程序是一个死锁现象。

为什么会发生死锁问题?

从运行结果上来看分析:

技术分享图片

 

 

改进后带来问题二:

 

Java-JUC(八):使用wait,notify|notifyAll完成生产者消费者通信,虚假唤醒(Spurious Wakeups)问题出现场景,及问题解决方案。

标签:分享   style   col   src   缺陷   生产   ack   public   包含   

原文地址:https://www.cnblogs.com/yy3b2007com/p/8946696.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!