以下のセクションでは、いくつかの最も一般的なデッドロック・シナリオを説明し、その回避方法を提示します。
結果、次の例外が表示されます。
com.ibm.websphere.objectgrid.plugins.LockDeadlockException: Message
このメッセージは、例外が作成されてスローされるときに、パラメーターとして渡されるストリングを表します。説明: トランザクションまたはクライアントが特定のマップ・エントリーに対するロックの 付与を求めると、その要求は、現在のクライアントがロックを解放するまで待機させられ、 その後、要求が実行依頼されることがしばしばあります。ロック要求が長い期間アイドル状態のままになり、いつまでも ロックが付与されない場合、デッドロックを回避するために LockTimeoutException 例外が 作成されます。デッドロックについては、次のセクションで詳しく説明します。ペシミスティック・ロック・ストラテジーを 使用すると、ロックはトランザクションがコミットするまで解放されないため、この例外が 発生する可能性がより高くなります。
詳細の取得
LockTimeoutException 例外は、ストリングを返す getLockRequestQueueDetails メソッドを 含んでいます。このメソッドを使用して、例外のトリガーとなった状態についての 詳細説明を確認できます。以下に、例外をキャッチして、エラー・メッセージを表示するサンプル・コードを示します。
try {
...
}
catch (LockTimeoutException lte) {
System.out.println(lte.getLockRequestQueueDetails());
}
lock request queue
−>[TX:163C269E−0105−4000−E0D7−5B3B090A571D, state =
Granted 5348 milli−seconds ago, mode = U]
−>[TX:163C2734−0105−4000−E024−5B3B090A571D, state =
Waiting for 5348 milli−seconds, mode = U]
−>[TX:163C328C−0105−4000−E114−5B3B090A571D, state =
Waiting for 1402 milli−seconds, mode = U]
try {
...
}
catch (ObjectGridException oe) {
Throwable Root = findRootCause( oe );
if (Root instanceof LockTimeoutException) {
LockTimeoutException lte = (LockTimeoutException)Root;
System.out.println(lte.getLockRequestQueueDetails());
}
}
解決策: LockTimeoutException 例外を使用して、アプリケーションでデッドロックが発生する 可能性を回避できます。このタイプの例外は、例外が一定時間待機すると 発生します。例外が待機する時間は、BackingMap で使用可能な setLockTimeout(int) メソッドを 使用して設定できます。アプリケーションで実際にはデッドロックが発生していない場合は、ロック・タイムアウトを 調整して、LockTimeoutException を回避してください。
ObjectGrid objGrid = new ObjectGrid();
BackingMap bMap = objGrid.defineMap("MapName");
bMap.setLockTimeout(30);
前のハードコーディングの例を使用して、ObjectGrid とマップのプロパティーを設定します。XML ファイルから ObjectGrid を 作成する場合は、backingMap エレメント内に LockTimeout 属性を設定してください。以下は、マップの LockTimeout 値を 30 秒に 設定する backingMap エレメントの例です。
<backingMap name="MapName" lockStrategy="PESSIMISTIC" lockTimeout="30">
説明: 以下のシナリオでは、S ロックを使用して単一キーにアクセスし、その後、そのキーを 更新するときにデッドロックがどのように発生するかを示しています。これが 2 つのトランザクションから同時に発生すると、デッドロックになります。
スレッド 1 | スレッド 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | 各スレッドが独立したトランザクションを確立します。 |
2 | map.get(key1) | map.get(key1) | key1 に対して S ロックが両方のトランザクションに認可されます。 |
3 | map.update(Key1,v) | U ロックはありません。更新はトランザクション・キャッシュで実行されます。 | |
4 | map.update(key1,v) | U ロックはありません。更新はトランザクション・キャッシュで実行されます。 | |
5 | session.commit() | ブロックされます。スレッド 2 が S ロックを保有しているため、key1 に対する S ロックは X ロックにアップグレードできません。 | |
6 | session.commit() | デッドロック: T1 が S ロックを保有しているため、key1 に対する S ロックは X ロックにアップグレードできません。 |
スレッド 1 | スレッド 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | 各スレッドが独立したトランザクションを確立します。 |
2 | map.get(key1) | key1 に対して S ロックが認可されます。 | |
3 | map.getForUpdate(key1,v) | key1 に対して S ロックが U ロックにアップグレードされます。 | |
4 | map.get(key1) | key1 に対して S ロックが認可されます。 | |
5 | map.getForUpdate(key1,v) | ブロックされます。T1 が既に U ロックを保有しています。 | |
6 | session.commit() | デッドロック: key1 に対する U ロックはアップグレードできません。 | |
7 | session.commit() | デッドロック: key1 に対する S ロックはアップグレードできません。 |
スレッド 1 | スレッド 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | 各スレッドが独立したトランザクションを確立します。 |
2 | map.get(key1) | key1 に対して S ロックが認可されます。 | |
3 | map.getForUpdate(key1,v) | key1 に対して S ロックが U ロックにアップグレードされます。 | |
4 | map.get(key1) | key1 に対して S ロックが認可されます。 | |
5 | map.getForUpdate(key1,v) | ブロックされます。スレッド 1 が既に U ロックを保有しています。 | |
6 | session.commit() | デッドロック: スレッド 2 が S ロックを保有しているため、key1 に対する U ロックは X ロックにアップグレードできません。 |
スレッド 1 | スレッド 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | 各スレッドが独立したトランザクションを確立します。 |
2 | map.getForUpdate(key1) | key1 のスレッド 1 に対して U ロックが認可されます。 | |
3 | map.getForUpdate(key1) | U ロック要求がブロックされます。 | |
4 | map.update(key1,v) | <blocked> | |
5 | session.commit() | <blocked> | key1 に対する U ロックは正常に X ロックにアップグレードできます。 |
6 | <released> | スレッド 2 に対して U ロックが最終的に key1 に認可されます。 | |
7 | map.update(key2,v) | key2 に対して U ロックがスレッド 2 に認可されます。 | |
8 | session.commit() | key1 に対する U ロックは正常に X ロックにアップグレードできます。 |
説明: このシナリオでは、2 つのトランザクションが同一エントリーを直接 更新しようとしたときに、他のエントリーに対して S ロックを保有しているとどうなるかを説明します。
スレッド 1 | スレッド 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | 各スレッドが独立したトランザクションを確立します。 |
2 | map.get(key1) | map.get(key1) | key1 に対して S ロックが両方のトランザクションに認可されます。 |
3 | map.get(key2) | map.get(key2) | key2 に対して S ロックが両方のトランザクションに認可されます。 |
4 | map.update(key1,v) | U ロックはありません。更新はトランザクション・キャッシュで実行されます。 | |
5 | map.update(key2,v) | U ロックはありません。更新はトランザクション・キャッシュで実行されます。 | |
6. | session.commit() | ブロックされます。スレッド 2 が S ロックを保有しているため、key1 に対する S ロックは X ロックにアップグレードできません。 | |
7 | session.commit() | デッドロック: スレッド 1 が S ロックを保有しているため、key2 に対する S ロックはアップグレードできません。 |
スレッド 1 | スレッド 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | 各スレッドが独立したトランザクションを確立します。 |
2 | map.getForUpdate(key1) | key1 に対して U ロックがトランザクション T1 に認可されます。 | |
3 | map.getForUpdate(key1) | U ロック要求がブロックされます。 | |
4 | map.get(key2) | <blocked> | key2 に対して S ロックが T1 に認可されます。 |
5 | map.update(key1,v) | <blocked> | |
6 | session.commit() | <blocked> | key1 に対する U ロックは正常に X ロックにアップグレードできます。 |
7 | <released> | T2 に対して U ロックが最終的に key1 に認可されます。 | |
8 | map.get(key2) | key2 に対して S ロックが T2 に認可されます。 | |
9 | map.update(key2,v) | key2 に対して U ロックが T2 に認可されます。 | |
10 | session.commit() | key1 に対する U ロックは正常に X ロックにアップグレードできます。 |
スレッド 1 | スレッド 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | 各スレッドが独立したトランザクションを確立します。 |
2 | map.getforUpdate(key1) | map.getForUpdate(key2) | key1 と key2 に対して U ロックが正常に認可されます。 |
3 | map.get(key2) | map.get(key1) | key1 と key2 に対して S ロックが認可されます。 |
4 | map.update(key1,v) | map.update(key2,v) | |
5 | session.commit() | T2 が S ロックを保有しているため、U ロックは X ロックにアップグレードできません。 | |
6 | session.commit() | T1 が S ロックを保有しているため、U ロックは X ロックにアップグレードできません。 |