0

TIJ4 P1208には、1つのコンシューマー(WaitPerson)と1つのプロデューサー(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

ここでの本当の問題は、2 つの条件が必要なことです (1 つは食事を待つ/食事を生産して通知する、もう 1 つは食事を待ってから食べる/食事を食べて通知する)。したがって、Bert F が言ったように、MEAL_READY と MEAL_NOT_READY のような任意の 2 つの異なるオブジェクトを使用できます。

同期キューであっても、より明確な方法で条件を使用してそれを行うことができます。

于 2012-08-15T00:39:45.470 に答える
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であるため、一度に「アクティブ」になる同期ブロックは 1 つだけです。not nullコードは、食事が、その後null、その後not nullなどになると、ブロックを交互に切り替えます。

同時アクセスからリソースを保護するために、リソース上のスレッドを同期するコードをよく目にします。同期のこの一般的な使用例では、上記のコードが直観に反しているように見える場合があります。これは、食事の「リソース」ではなく、Runnable オブジェクト (chef と waitperson) で同期します。

ただし、食事はこの場合の同期に使用するのに理想的ではありません。これは、食事の寿命が非常に短く、コードが複数のスレッドによる同時アクセスから食事を保護することを意図していないためです。むしろ、このコードはプロデューサー スレッドとコンシューマー スレッドを調整しようとしているだけです。これらのスレッドを調整するために、より安定した長寿命のインスタンスを使用することは、短命の食事インスタンスを使用するよりも簡単です。

インスタンスが存在し、スレッドがどのインスタンスを使用してどのような条件下で同期するかについて合意している限り、同期に何を使用してもかまいません。コードは、MEAL_READY および MEAL_NOT_READY と呼ばれる同期に使用する 2 つの任意のクラスの 2 つの任意のトークン インスタンスを作成できます。ただし、chef と waitperson のインスタンスは、同期に使用する、便利で既製の、長寿命のインスタンスを作成します。

于 2010-11-06T03:36:19.797 に答える