第3回 ある条件が満たされるまで処理を待たせる
皆さんはポーリングループをご存知でしょうか?
ある条件が満たされるまで処理を待たせるため、 ループを繰り返し、処理を進めない手法です。
条件が満たされるまで処理を待ちたいという事は実際の現場では よくあることだと思います
しかし、ポーリングループはパフォーマンスを低下させてしまいます。
そこで、ポーリングループを使用せず、条件が満たされるまで待ちたい場合 マルチスレッドで使用するwaitメソッドと notifyAllメソッドの待ち合わせを 利用します。
以下のサンプルは「肉を焼く」スレッドと 「肉を食べる」スレッドが存在します。 「肉を焼く」スレッドでは肉を使用する権利を得る (synchronizedでロックする)前に 1秒間空けているため、 先に「肉を食べる」スレッドが権利を得て動き出します。
しかし、肉の状態が「焼き」に変わるまでwaitメソッドで待機します。 その際、whileループにて条件判定を行っていますが、 ポーリングループではありません。 処理は、waitメソッドにて待機状態となります。 ifでもよいのですが何らかの手違いにより waitメソッドによる待機状態が解除されるのを防ぐために whileループを使用しています。
// バーベキュークラス
public class Bbq {
private Meat meat = new Meat();
public static void main(String[] args) throws Exception {
Bbq party = new Bbq();
party.start();
}
public void start() {
new Thread(new Runnable(){
public void run() {
try {
Thread.sleep(1000);
synchronized (Bbq.this.getMeat()) {
System.out.println("肉を焼き始めました。");
Thread.sleep(5000);
// 肉を焼く(5秒程度)
Bbq.this.broil();
// 焼き上がりを報告
System.out.println("肉が焼けました。");
Bbq.this.getMeat().notifyAll();
}
} catch (Exception e) {
throw new Error("肉を焼くのに失敗しました。", e);
}
}
}).start();
new Thread(new Runnable(){
public void run() {
try {
synchronized (Bbq.this.getMeat()) {
// 焼き上がり待ち
System.out.println("肉を食べよう!!");
while(Bbq.this.getMeat().getCondition() !=
MEAT_CONDITION.GRILLED) {
System.out.println("まだ焼けてない(ToT)/");
Bbq.this.getMeat().wait();
}
// 食べる
System.out.println("やったーー食べるぞーー!!!");
Bbq.this.eat();
System.out.println("肉を食べ終わりました");
}
} catch (Exception e) {
throw new Error("肉を食べるのに失敗しました。", e);
}
}
}).start();
}
// 肉焼きメソッド
public void broil() {
meat.setCondition(MEAT_CONDITION.GRILLED);
}
// 肉食いメソッド
public void eat() {
meat = null;
System.out.println("肉を食べました。");
}
// 肉データ取得メソッド
public Meat getMeat() {
return meat;
}
}
//肉の状態
enum MEAT_CONDITION {
RAW,
GRILLED
}
// 肉データ
class Meat {
private MEAT_CONDITION condition = MEAT_CONDITION.RAW;
public MEAT_CONDITION getCondition() {
return condition;
}
public void setCondition(MEAT_CONDITION condition) {
this.condition = condition;
}
}
肉が焼けるまで5秒待ってね!!

