论坛首页 Java企业应用论坛

Java并发实现生产者消费者模式

浏览 8222 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (4)
作者 正文
   发表时间:2011-07-24  

这个例子有点局限,消费者每次只能等生产者生产了n个Q后消费完这n个。

 

package com.test;

class Q { 
	int n; 
	boolean valueSet = false; //Q的value是不是已经设置过了
	synchronized int get() { 
		if(!valueSet) 
			try { 
				wait(); //wait until Producer produce a product and notify  -----A
			} catch(InterruptedException e) { 
				System.out.println("InterruptedException caught"); 
			} 
		System.out.println("Got: " + n); 
		valueSet = false; 
		notify(); 
		return n; 
	} 
	
	synchronized void put(int n) { 
		if(valueSet) 
			try { 
				wait(); 
			} catch(InterruptedException e) { 
				System.out.println("InterruptedException caught"); 
			} 
		this.n = n; 
		valueSet = true; 
		System.out.println("Put: " + n); 
		notify(); 
	} 
}

class Producer implements Runnable { 
	Q q;
	
	Producer(Q q) { 
		this.q = q; 
		new Thread(this, "Producer").start(); 
	}
	
	public void run() { 
		int i = 0; 
		while(true) { 
			q.put(i++); 
		} 
	} 
}

class Consumer implements Runnable { 
	Q q;
	
	Consumer(Q q) { 
		this.q = q; 
		new Thread(this, "Consumer").start(); 
	} 
	
	public void run() { 
		while(true) { 
			q.get(); 
		}	 
	} 
}

class PCFixed { 
	public static void main(String args[]) { 
		Q q = new Q(); 
		new Consumer(q); 
		new Producer(q); 

		System.out.println("Press Control-C to stop."); 
	} 
}

 

可是这里我有一个疑问,如果Consumer的线程先运行,调用get方法,在A处wait。接着Producer的线程运行,调用put方法,但是因为put是synchronized方法,不是应该等待get方法退出才能执行,这样不是应该死锁了么。但我执行过很多次,并不会死锁,这是为什么呢?还有,怎么在问答频道发帖呢?

   发表时间:2011-07-24  
1、wait的时候会释放该对象的同步锁,这时其他线程是可以获得该对象的同步锁的。wait退出后会重新获得同步锁(在jvm里完成、并且包括异常的情况)。所以你的代码逻辑基本上是没有问题的,也不会有死锁。
2、最好把if(condition) wait() 改成 while(condition) wait()
3、你这个demo更像是Exchanger。典型的生产者/消费者模式是用队列缓存任务的,这样在一定程度上生产者和消费者是基于流水线的方式持续运行的,不必每次生产或消费都要等待对方。
0 请登录后投票
   发表时间:2011-07-25  
taolei0628 写道
1、wait的时候会释放该对象的同步锁,这时其他线程是可以获得该对象的同步锁的。wait退出后会重新获得同步锁(在jvm里完成、并且包括异常的情况)。所以你的代码逻辑基本上是没有问题的,也不会有死锁。
2、最好把if(condition) wait() 改成 while(condition) wait()
3、你这个demo更像是Exchanger。典型的生产者/消费者模式是用队列缓存任务的,这样在一定程度上生产者和消费者是基于流水线的方式持续运行的,不必每次生产或消费都要等待对方。

谢谢,您说的是对的
0 请登录后投票
   发表时间:2011-07-26  
请在 循环中 调用。Object.wait() 。具体请参照 Java API Doc。
if(!valueSet) 
改成
while(!valueSet)

if(valueSet) 
改成
while(valueSet)
0 请登录后投票
   发表时间:2011-07-26  
不换成while肯定是有问题的。
0 请登录后投票
   发表时间:2011-07-26  
小牛犊 写道
不换成while肯定是有问题的。

能解释下为什么不
0 请登录后投票
   发表时间:2011-07-26  
新手来学习学习
0 请登录后投票
   发表时间:2011-07-26  
chriszeng87 写道
小牛犊 写道
不换成while肯定是有问题的。

能解释下为什么不


chriszeng87 写道

消费者每次只能等生产者生产了n个Q后消费完这n个
,被你的n个Q给害了,你这只有一个生产者和一个消费者。


0 请登录后投票
   发表时间:2011-07-26  
用BlockingQueue实现比较简单,呵呵
0 请登录后投票
   发表时间:2011-07-27  
应该是指“监视条件”吧,对象等待一般是条件不符合,对象被通知不一定符合执行的条件。当然就二个线程的时候跑起来挺欢的。多个线程使用notifyAll时可能就出问题了。而多个线程这种场景是最常见的。所以一般是while(条件不符合){wait();}

chriszeng87 写道
小牛犊 写道
不换成while肯定是有问题的。

能解释下为什么不

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics