Java 4中思考的单一生产者和消费者示例

时间:2010-11-06 02:55:34

标签: java multithreading producer-consumer

在TIJ4 P1208中,有一个消费者(WaitPerson)和一个生产者(Chef)。当检查是否有可用餐时,每个都自动同步。我认为他们应该在用餐时同步。否则,当服务员检查是否有餐时,厨师很可能正在制作餐,这使得餐厅在服务员检查时处于不一致的状态。

你们怎么想? 感谢

这是代码:

import java.util.concurrent.;
import static net.mindview.util.Print.;

class Meal { private final int orderNum; public 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(); // ... for the chef to produce a meal } print("Waitperson got " + restaurant.meal); synchronized(restaurant.chef) { restaurant.meal = null; restaurant.chef.notifyAll(); // Ready for another } } } catch(InterruptedException e) { print("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) { print("Out of food, closing"); restaurant.exec.shutdownNow(); } printnb("Order up! "); synchronized(restaurant.waitPerson) { restaurant.meal = new Meal(count); restaurant.waitPerson.notifyAll(); } TimeUnit.MILLISECONDS.sleep(100); } } catch(InterruptedException e) { print("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(); } } /* Output: Order up! Waitperson got Meal 1 Order up! Waitperson got Meal 2 Order up! Waitperson got Meal 3 Order up! Waitperson got Meal 4 Order up! Waitperson got Meal 5 Order up! Waitperson got Meal 6 Order up! Waitperson got Meal 7 Order up! Waitperson got Meal 8 Order up! Waitperson got Meal 9 Out of food, closing WaitPerson interrupted Order up! Chef interrupted *///:~

2 个答案:

答案 0 :(得分:0)

  

否则,当服务员检查餐点是否可用时,厨师很可能正在制作餐食

不,看看在相同的对象上同步时主厨和服务员正在做什么:

synchronized on waitPerson:
   - waitperson is looking for meal [while (meal == null)]
   - chef is creating a meal [meal = new Meal()]
   - waitperson cannot look for meal exactly while chef is creating meal
   - waitperson waits/sleeps until meal is ready
   - chef notifies all when meal is created, which wakes waitperson


synchronized on chef:
   - waitperson is taking the meal [meal = null]
   - chef is waiting for meal to be taken [while (meal != null)]
   - chef cannot check if meal has been taken exactly while the waitperson is taking the meal
   - chef waits/sleeps until meal is taken
   - waitperson notifies all when meal is taken, which wakes chef

因为用餐是nullnot null,所以一次只有一个同步块处于“活动状态”。当膳食变为not null,然后是null,然后是not null等时,代码会在块之间交替显示。

您经常会看到同步资源上的线程的代码,以防止资源同时访问。这种同步的常见用例可能会使上面的代码看起来违反直觉 - 它在Runnable对象(厨师和服务员)上同步,而不是用餐“资源”。

但是,在这种情况下,用餐不适合用于同步,因为它们非常短暂且代码旨在保护膳食多线程同时访问。相反,代码只是试图协调生产者和消费者线程。使用更稳定,寿命更长的实例来协调这些线程比使用寿命较短的用餐实例更简单。

只要实例存在并且线程同意在什么条件下用于同步的实例,它们用于同步的内容并不重要。代码可以创建两个任意类的两个任意标记实例,用于同步,称为MEAL_READY和MEAL_NOT_READY。但是,chef和waitperson实例可以使用方便的,现成的,长期存在的实例来进行同步。

答案 1 :(得分:0)

这里真正的问题是你需要两个条件(1等待用餐/生产餐和通知,另一个等待吃饭/吃饭和通知)。所以你可以使用任何两个不同的对象,如Bert F所说的MEAL_READY和MEAL_NOT_READY。

即使使用同步队列,您也可以通过更清晰的方式处理条件。