Revised: Apr./6th/2002
前節では、他のスレッドの実行が終了するまで待機する形でマルチスレッドの同期を取りました。この場合は、同期のタイミングを、スレッドの制御の途中にすることはできません。また、待機する自分と同期を取る相手の二者間の同期であって、特定のスレッドから特定のスレッドを操作する形の同期も実現できません。
このような課題はスレッドのモニタと、メソッドや変数のロックと言う形で解決します。
ロックが必要な場合を考えます。例えば、あるスレッドは有限の値を取得し、一定量を別の量に加算してから、加えた量を元の量から減算するとします。このようなスレッドが複数平行して実行されている場合、タイミングが合っていれば、元々保持されていた量以上は加算しないですみます。しかし、タイミングがずれると、あるスレッドが量を取得して加算する間に、別のスレッドが加算と減算の両方を実行しているかもしれません。こうなると、加算量を元の量以下にとっても、既に元の量が0である場合が発生します。
このような不整合を回避する為に、元になる量やその量へのアクセスメソッドをロックしておきます。こうすることで、あるスレッドがアクセスしている間は別のスレッドが操作できないので、先に見たような不整合を回避できます。
ロックと言うのは、当該コードに対する実行権を与える為のトークンです。オブジェクトの同期指定されたコードを利用しようとするスレッドは、そのロックを取得して初めて利用できます。
同期指定は、 synchronized
宣言により実現します。
他のスレッドが利用しているなどの理由で、ロックが取得できない場合は、ロック探索状態になります。
一方、ロックを取得しているスレッドは、当該コードから制御が外れると、ロックを解放し、他のスレッドがロックを取得できるようになります。
この仕組みによって、同期指定されたコードは、複数のスレッドから同時にアクセスされることがなくなり、データの保護と同期を実現できます。
モニターというのは、スレッドのブロックと回復を行うオブジェクトです。
例えば、 JavaVM の外部からのデータの入力で、入力すべきデータが存在しなかったり、当該リソースがビジーだった場合は、そのメソッドは実行待機状態に入りますが、実行中の状態から退いた状態がブロック状態です。
ブロック状態を明示的に生み出すには wait()
メソッドを用い、回復には notify()
メソッドを用います。また、同期指定されたコードのロックを取得しようと試みているときもブロック状態になります。モニターと言うのは、このような方法でスレッドの排他制御を行うオブジェクトのことです。
簡単に言うと、 synchronized
によって同期指定されたコードを持つオブジェクトがモニターです。