0

在 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 *///:~

4

2 回答 2

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

因为进餐是nullor not null,所以一次只有一个同步块是“活动的”。代码在块之间交替,因为饭变成了not null,然后null,然后not null,等等。

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

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

只要实例存在并且线程同意在什么条件下使用什么实例进行同步,它们使用什么来同步并不重要。该代码可以创建两个任意类的两个任意令牌实例以用于同步,称为 MEAL_READY 和 MEAL_NOT_READY。但是,厨师和服务员实例提供了方便的、现成的、长期存在的实例以用于同步。

于 2010-11-06T03:36:19.797 回答
0

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

即使使用同步队列,您也可以以更清晰的方式使用条件来做到这一点。

于 2012-08-15T00:39:45.470 回答