生产者消费者[简单示例]

class Meal{
	private final int orderNum;
	Meal(int orderNum){
		this.orderNum = orderNum;
	}
	public String toString(){
		return "Meal " + orderNum;
	}
}

class WaitPerson implements Runnable{
	private Restaurant restaurant;
	public WaitPerson(Restaurant r){
		restaurant = r;
	}
	public void run(){
		try {
			while (!Thread.interrupted()) {
				synchronized (this) {
					while (restaurant.meal == null)
						wait();
				}
				System.out.println("Waitperson got " + restaurant.meal);
				synchronized (restaurant.chef) {
					restaurant.meal = null;
					restaurant.chef.notifyAll(); // ready for another
				}
			}
		} catch (Exception e) {
			System.out.println("WaitPerson interrupted");
		}
	}
}
class Chef implements Runnable{
	private Restaurant restaurant;
	private int count = 0;
	public Chef(Restaurant r){
		restaurant = r;
	}
	public void run(){
		try {
			while(!Thread.interrupted()){
				synchronized(this){
					while(restaurant.meal!=null)
						wait(); 	// for the meal to be taken;
				}
				if(++count == 10){
					System.out.println("Out of fodd, clsosing");
					restaurant.exec.shutdownNow();
				}
				System.out.println("Order up! ");
				synchronized(restaurant.waitPerson){
					restaurant.meal = new Meal(count);
					restaurant.waitPerson.notifyAll();
				}
				TimeUnit.MILLISECONDS.sleep(100);
			}
		} catch (InterruptedException e) {
			System.out.println("Chef interrupted");
		}
	}
}

public class Restaurant {
	Meal meal;
	ExecutorService exec = Executors.newCachedThreadPool();
	WaitPerson waitPerson = new WaitPerson(this);
	Chef chef = new Chef(this);
	public Restaurant(){
		exec.execute(chef);
		exec.execute(waitPerson);
	}
	public static void main(String[] args) {
		new Restaurant();
	}
}

 

 

Restaurant是WaitPerson和Chef的焦点, 他们都必须子回到在为哪个Restaurant工作,

因为他们必须和这家饭店的“餐窗”打交道, 以便放置或拿取restaurant.meal。 在run()

中, WiatPerson进入wait()模式, 停止其任务, 直到被Chef的notifyAll()唤醒。

 

由于这是一个非常简单的程序,因此我们直到只有一个任务将在WaitPerson的锁上

等待,即WaitPerson任务自身。 出于这个原因, 理论上可以调用notify()而不是

notifyAll()。 但是,在更复杂的情况下,可能会有多个任务在某个特定对象上

等待,因此就不知道哪个任务应该被唤醒,因此,调用notifyAll()更安全些,

这样可以唤醒等待这个锁的所有任务, 而每个任务都必须决定这个通知是否与

自己相关。

 

注意, wait()被包装在一个while()语句中, 这个语句在不断地测试正在等待的食物。

看上去有点怪-- 如果在等待一个订单,一旦被唤醒,这个订单就必须是可获得的,对嘛?

正如前面注意到的, 问题是在并发应用中, 某个洽谈的任务可能会在WaitPerson被唤醒,

会突然插足拿走订单,唯一安全的方式是使用下面这种wait()的惯用法

while(conditionIsNotMet)

wait();

 

对notifyAll()的调用必须首先捕获waitPerson上的锁, 而在WatiPerson.run()中

的对wati()的调用会自动地释放这个锁, 因此这是有可能实现的。 因为调用

notifyAll()必然拥有这个锁, 所以这保证两个试图在统一个对象上调用notifyAll()

的任务不会相互冲突。

 

通过把整个run()方法体放到一个try语句块中, 可使得这2个run()方法都被设计为

可以有序地关闭。 catch自居将紧挨着run()方法的结束括号之前结束,因此,如果这个任务

收到了InterruptedException异常, 它将在捕获异常之后立即结束。

 

注意, 在Chef中, 在调用shutdownNow()之后, 应该直接从run()中返回,并且通常这就是

你应该做的。 但是,以这种方式执行还有一些更有趣的东西。 shutdownNow()将向所有

由ExecutorService启动的任务发送interrupt(), 但是在Chef中,任务并没有获得该

interrupt()之后立即关闭, 因为当任务试图进入一个(可中断的)阻塞操作时,这个

中断只能抛出InterruptedException。 因此, 将看到首先显示了 "Order up!",然后

当Chef试图调用Slee()时, 抛出了InterruptedException. 如果移除对slee()的调用,

那么这个任务将回到run()循环的顶部,并由于Thread.interrupted()测试而退出,

同时并不抛出异常。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值