FM牛鍵屋本舗

プログラマ(弱)の日々精進系ブログ

synchronizedブロックとwaitに関する仮説

JavaGoldの資格勉強してて、 「なんでsynchronizedブロックでしかwait/notify/notifyAll使えないんだろう?」 と疑問に思ったので考えてみた。

間違ってるとは思うのでツッコミ待ち。

メソッド名から考えてみる

まず、Threadを一時中止するメソッドとして

java.lang.Thread.sleep

がある。 上記のクラス、メソッド名で考えると「Treadが眠る」となる。

一方、

java.lang.Object#wait

こちらは、「オブジェクトが待つ」。 何を待つか。おそらく状態の変化だ。

つまり、いずれも自身へのCPU割当を解除し、他Treadへ移譲するように JVMに指示するメソッドではあるが、 目的語があるかどうか、すなわち他と関連するかどうか、という点で異なっている。

synchronized

synchronizedは「オブジェクトにロックをかける」修飾子。 リソースにロックをかけて処理の原子性とリソースの完全性を担保する。 逆に言うと、synchronizedブロック外は(マルチスレッド環境においては) いつ何時他のThreadの処理が行われても構わない、ということになる。

組み合わせで考えてみる

synchronizedの有無とsleep/waitの組み合わせで考えてみる。

① synchronizedなしのsleep

よくあるパターン(かどうかはわからないが)。 単にちょっと待って他のTreadに何らかの処理をさせる。 他の処理の結果は、原則的に当該処理に影響が出ない。 まあinterrup()とかしたら別だけど…。

② synchronizedなしのwait

※ もちろん実際にはIllegalMonitorStateExceptionが発生する。 他の処理に何かを期待して待つ。 あるとき、自Threadが望んだ状態になる。 しかし、その後の処理を行って居る際に割り込みが発生し、望んだ状態でなくなるかもしれない。 それを防ぐには、synchronizedを使うしかない…。

③ synchronizedありのsleep

対象リソースはロックされているので、それが変更されることはないが 一時的に自身の処理を止めることは出来る。

④ synchronizedありのwait

自身が望む状態を他のTreadに作り出してほしい。 なので、ロック対象のオブジェクトを変更する許可を出す。

こんな感じ?