多线程-生产者消费者

正解博客: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);
            }
        }
        }
}

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

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

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

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

猜你喜欢

转载自www.cnblogs.com/Andrew520/p/8881635.html