「増補改訂版 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 ページより)