デッドロックは、プログラム内の1つ以上のスレッドがリソースにアクセスできなくなるか、待機状態のままいつまでも処理できない場合に発生します。Javaでの一般的なデッドロックは、モニター・ブロック・サイクル・デッドロックです。
モニター・ブロック・サイクル・デッドロックは、複数のスレッドが、他のスレッドがすでに実行中の同期コードを実行するために待機し、処理ができなくなる場合に発生します。
次に典型的なJavaの同期デッドロックの例を示します。
スレッド1は次のコードを実行しています。
synchronized (a) { ... synchronized (b) { ... } ... }同時に、スレッド2は次のコードを実行しています。
synchronized (b) { ... synchronized (a) { ... } ... }
スレッド2がsynchronized (b)
を実行中、スレッド1がsynchronized (a)
に入るとデッドロックが発生します。 スレッド1は、スレッド2がsynchronized (b)
を終了するまでsynchronized (b)
に入ることができず、スレッド2は、スレッド1がsynchronized (a)
を終了するまでsynchronized (a)
に入ることができません。デッドロックは「デッドリ・エンブラス」とも呼ばれます。この例ではスレッドは2つですが、スレッドの数が3つ以上ある場合にも同じような状況が発生します。デッドロック・ブレークポイントでは、このようなタイプのデッドロックを検出できます。
1つのスレッドが特定のオブジェクトでwait
メソッドをコールし、他のスレッドがそのオブジェクトでnotify
メソッドをコールしない場合にもデッドロックが発生します。このタイプのデッドロックの最も一般的な原因はタイミングです。 待機側のスレッドがwait
をコールする前に、通知側のスレッドがnotify
をコールした可能性があります。 wait
をコールする場合に注意が必要な点は、notify
が前に何度もコールされていたとしても、wait
メソッドはnotify
がもう1度コールされるまで待機するという点です。また、待機しているスレッドがない場合、notify
はエラーを返しません。デッドロック・ブレークポイントでは、このタイプのデッドロックは検出できません。
プログラムがハングしている可能性がある場合は、デバッガで「プログラムの停止」()を使用してプログラムを一時停止し、「モニター」ウィンドウを開きます。コードを調べて、待機しているスレッドを見つけます。最初のスレッドが
wait
をコールする前に別のスレッドがnotify
をコールしている場合はデッドロックが発生しています。このタイプのデッドロックの検出は非常に困難です。 他のどのスレッドがnotify
をコールしたかを検出するには、作成したコードをよく理解しておく必要があります。
JDeveloperのデバッガでは、実行を開始すると永続デッドロック・ブレークポイントが設定されます。デッドロック・ブレークポイントは、デッドロックのソースの場所を特定するのが困難な場合に便利です。デバッガは、デッドロック・ブレークポイントに達すると停止します。デバッガは、前述のモニター・ブロック・サイクル・デッドロックを検出できます。モニター・ウィンドウは、デッドロックを処理する場合に有益です。
デッドロック・ブレークポイントには、次の特徴があります。
JDeveloperのデバッガでは、永続デッドロック・ブレークポイントが自動的に作成されます。このブレークポイントは、モニター・ブロック・サイクルが検出されるたびに発生します。永続ブレークポイントは削除できません。新規デッドロック・ブレークポイントの作成はできませんが、既存の永続デッドロック・ブレークポイントの編集は可能です。
デッドロック検出がサポートされていないJava Virtual Machineもあります。たとえば、HotSpot VMでは、デッドロック検出はサポートされていません。
Copyright © 1997, 2004, Oracle. All rights reserved.