多线程-生产者消费者

正解博客:https://blog.csdn.net/u011863767/article/details/59731447

永远在循环(loop)里调用 wait 和 notify,不是在 If 语句

现在你知道wait应该永远在被synchronized的背景下和那个被多线程共享的对象上调用,下一个一定要记住的问题就是,你应该永远在while循环,而不是if语句中调用wait。因为线程是在某些条件下等待的——在我们的例子里,即“如果缓冲区队列是满的话,那么生产者线程应该等待”,你可能直觉就会写一个if语句。但if语句存在一些微妙的小问题,导致即使条件没被满足,你的线程你也有可能被错误地唤醒。所以如果你不在线程被唤醒后再次使用while循环检查唤醒条件是否被满足,你的程序就有可能会出错——例如在缓冲区为满的时候生产者继续生成数据,或者缓冲区为空的时候消费者开始小号数据。所以记住,永远在while循环而不是if语句中使用wait!我会推荐阅读《Effective Java》,这是关于如何正确使用wait和notify的最好的参考资料。

有的这样说:(http://www.tuicool.com/articles/a6ram23)

因为在多核处理器环境中, Signal 唤醒操作可能会激活多于一个线程(阻塞在条件变量上的线程),使得多个调用等待的线程返回。所以用while循环对condition多次判断,可以避免这种假唤醒。

基于以上认知,下面这个是使用wait和notify函数的规范代码模板:


1

2

3

4

5

6

7

8

// The standard idiom for calling the wait method in Java

synchronized(sharedObject) {

    while(condition) {

    sharedObject.wait();

        // (Releases lock, and reacquires on wakeup)

    }

    // do action based upon condition e.g. take or put into queue

}

就像我之前说的一样,在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足。如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那么这个线程并不能保证被唤醒,有可能会导致死锁问题。

注意:

1 永远在synchronized的方法或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。

2 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。

3 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。

生产者消费者代码:

https://zhuanlan.zhihu.com/p/20300609 代码有部分问题,修改如下

ProsumerToConsumer类
public class ProsumerToConsumer {

    public static void main(String[] args) throws Exception {

        Person person =new Person();
        Thread t1=new Thread(new Producer(person),"生产者t1");
        Thread t2=new Thread(new Producer(person),"生产者t2");
        Thread t3=new Thread(new Producer(person),"生产者t3");
        Thread s1=new Thread(new Consumer(person), "消费者s1");
        Thread s2=new Thread(new Consumer(person), "消费者s2");
        Thread s3=new Thread(new Consumer(person), "消费者s3");

        s1.start();
        s2.start();
        Thread.sleep(2000);
        t1.start();
        t2.start();
        t3.start();

    }

}

  producer代码:

public class Producer implements Runnable {

    private Person person;
//    private String name;

     public Producer( Person person) {
         this.person=person;
//         this.name=name;
    }

    @Override
    public void run() {
        try {
            person.producer();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

  consumer代码:

public class Consumer implements Runnable{

    private Person person;

     public Consumer( Person person) {
         this.person=person;
    }

    @Override
    public void run() {

        try {
            person.consumer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  person代码:

public class Person {

    private static volatile int num=0;
    private Object obj= new Object();

    private static final int MAX_NUM=5;

    public void producer()throws InterruptedException{

        while(true){
            synchronized (obj) {
                while(num==MAX_NUM) {
                    System.out.println("box is full,size = " + num);
                    obj.wait();
                }
                num++;
                System.out.println( Thread.currentThread().getName()+ num);
                obj.notifyAll();
            }
        }
    }

    public void consumer() throws InterruptedException{
        while (true) {
            synchronized (obj) {
                while (num==0) {
                    System.out.println("box is empty,size = " + num);
                    obj.wait();
                }
                num--;
                obj.notifyAll();
                System.out.println(Thread.currentThread().getName() + num);
            }
        }
        }
}

实例验证1:如果判断用的是while  数据在队列容量范围之内。

while(num==MAX_NUM)
        while(true){
            synchronized (obj) {
                while(num==MAX_NUM) {
                    System.out.println("box is full,size = " + num);
                    obj.wait();
                }

实例验证2:如果判断用的是if  ,数据已经超出了队列的容量

if(num==MAX_NUM) 
        while(true){
            synchronized (obj) {
                if(num==MAX_NUM) {
                    System.out.println("box is full,size = " + num);
                    obj.wait();
                }

原文地址:https://www.cnblogs.com/Andrew520/p/8881635.html

时间: 2024-08-28 06:03:21

多线程-生产者消费者的相关文章

多线程生产者/消费者模式实现

参考书籍<java多线程编程核心技术> 都是基于wait/notify实现的 一个生产者和一个消费者:操作值 1 package com.qf.test10.pojo; 2 3 /** 4 * @author qf 5 * @create 2018-09-18 15:59 6 */ 7 public class Entity { 8 public static String value = ""; 9 } 1 package com.qf.test10; 2 3 impor

多线程生产者消费者问题处理

一.比较低级的办法是用wait和notify来解决这个问题. 消费者生产者问题: 这个问题是一个多线程同步问题的经典案例,生产者负责生产对象,消费者负责将生成者产生的对象取出,两者不断重复此过程.这过程需要注意几个问题: 不论生产者和消费者有几个,必须保证: 1.生产者每次产出的对象必须不一样,产生的对象有且仅有出现一次: 2.消费者每次取出的对象必须不一样,取出的对象有且仅有出现一次: 3.一定是先产生该对象,然后对象才能被取出,顺序不能乱: 第一种情况:多个生产者轮流负责生产,多个消费者负责

java多线程 生产者消费者模式

package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static void main(String[] args) { Godown godown = new Godown(50); for (int i = 0; i < 5; i++) { new ProducerThread(i * 10, godown).start(); new ConsumerThre

[多线程] 生产者消费者模型的BOOST实现

说明 如果 使用过程中有BUG 一定要告诉我:在下面留言或者给我邮件(sawpara at 126 dot com) 使用boost::thread库来实现生产者消费者模型中的缓冲区! 仓库内最多可以存放 capacity 个产品. 条件变量 condition_put 标记是否可以往仓库中存放一个产品. 条件变量 condition_get 标记是否可以从仓库中取出一个产品. 互斥量 mutexer 用于保证当前仓库只有一个线程拥有主权. 实现 #include <queue> #inclu

多线程生产者消费者模式

闲着没事,写了个生产者消费者模式玩玩,顺便熟悉下notify的用法. package sync; public class Test { public static void main(String[] args) { Test test = new Test(); Producer producer = test.new Producer(); producer.start(); Consumer consumer = test.new Consumer(); consumer.setName

多线程生产者消费者案例

题目需求:写一个生产者消费者容器,支持多个生产者消费者同时访问,容器里最多放十个数,需要get()和put()方法,当容器中没数据时,生产者开始生产数据,消费者等待,数据量满十个时,生产者等待,消费者开始消费. /** * Created by canner on 2018/11/30. */ public class MyContainer<T> { private final int MAX = 10; private final LinkedList<T> list = ne

多线程--生产者/消费者线程模型

//程序演进1 //thread loop,忙等Busy wait //不断的检查是不是该做什么事情了:为了减少CPU占用,sleep睡眠一会 //while (1) //{ // do_something(); // sleep(time); //} //程序演进2 //while (1) //{ // read_form_intput(); // do_something(); //} //程序员演进3,消息模型 //while (waitForMsg) //{ // if (isQuitM

java 多线程-生产者消费者模式-管程法

生产者消费者模式管程法通过容器中介,将数据放入和取出 wait()导致当前线程等待,直到另一个线程调用该对象的notify()或notyfyAll()方法notify()唤醒正在等待对象监视器的单个线程,notifyAll()唤醒正在等待对象监视器的所有线程 public class tuble { public static void main(String[]args) { SynContainer container=new SynContainer(); new Productor(co

java 多线程生产者消费者

class Res { private String name; private int count = 1; private boolean flag; public synchronized void set(String name) { while (flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name + "--" + cou