Hatena::ブログ(Diary)

midousujikunの日記

2012-03-18

Balking パターン



第四章に突入.この章では Balking パターンについて学ぶ,

第三章で学んだ Guarded Suspension パターンではスレッドのガード条件が満たされていなかった場合は,ガード条件が満たされるまで待ち続けていた.Balking パターンでもガード条件が登場するのは同様だが,Guarded Suspension パターンとは異なり,ガード条件が満たされない場合にはすぐに処理を中断する.

この章で作成するサンプルプログラムでは,簡単なデータ自動保存プログラムのようなものである.データを変更し,しばらく間をおいた後保存を行うスレッドと,定期的にデータの変更を見に行き,変更されていた場合には保存を行うスレッドとの動きを見る.このプログラムでのガード条件は「データが変更されたか」であり,ガード条件が満たされていなかった場合には各スレッドは処理を balk する.

ようやく実用的なプログラムに使えそうな技術が出てきてテンションが上がってきた.この調子で今月末までにひと通りこの本の内容を終わらせたい.

「増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編」第三章『Guarded Suspension』読了



ちょっと間があいたが読み終わった.

ガード条件は if ではなく while

演習問題 3-4 (133 ページ) より.この章で扱っているサンプルプログラムでは,キューにリクエストを追加するスレッドとキュからリクエストをとりだし処理を行うスレッドの 2 種類が,ガード条件によって正常に処理を繰り返すことを目的としている.ここで,リクエストを取り出し処理を行う方のスレッドでは以下のようなガード条件が課されている.

public synchronized Request getRequest () {
    try {
	while ( queue.peek() == null ) {
		wait();
	    }
	} catch ( InterruptedException e ) {
    }
    return queue.remove();
}
(117 ページ List.3.2 より)

ここでは,queue.peek () == null がガード条件となっており,キューの中にリクエストがひとつもない場合は wait () でウェイトセットに入り,notifyAll がされるまで queue.remove() によるキューからのリクエスト取り出し処理を待ち続けるというものである.

では,このプログラム内でのガード条件部分を while から if に書き直すとどうか?

もし,複数のインスタンスがウェイトセットに入っていた場合,notifyAll によってすべてのインスタンスの待ち状態が解除される.その際にキューにリクエストが 1 個しかなかったならば,2 つ目以降のインスタンスは空っぽにもかかわらず queue.remove () を行うため,エラーが起こってしまう.

ここでは notifyAll がされるたびにガード条件を確かめ,本当にキューの中にリクエストがあるのかどうかを確認しなければならない,そのため,ガード条件の確認には if 文ではなく while 文を使用しなければならない.

wait と sleep の違い

演習問題 3-4 (133 ページ) より.イマイチ違いがわかっていなかった.両者の違いは,「ロックの解放」にある.

wait を実行したスレッドは,対象になっているインスタンスのロックを解放します.一方,Thread.sleep はインスタンスのロックを解放しません.
(495 ページより)


上記のプログラム内の wait(); を Thread.sleep (100); に変更したとする.すると,インスタンスのロックはかかったままなので定期的に目を覚ますが,何の処理も進まないプログラムになってしまう.

動いてはいるけれども実質的にまったく先に進まない状況のことを,一般にライブロック (livelock) と呼びます.
(495 ページより)