第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秒待ってね!!