29.4.5. デッドロック

本項ではデッドロックの問題を発見して解決する方法について説明しています。 何が Mbean をデッドロックしているか、 使用しているアプリケーション内でデッドロックをどのようにして検出するか、そしてデッドロックをどのようにしたら解決できるのかなどについて説明していきます。デッドロックは 複数のスレッドが共有リソース上でロックしている場合に発生する可能性があります。図29.8「デッドロックの定義例」 では、シンプルなデッドロックの発生例を示します。以下では、 Thread 1Bean Aのロック、Thread 2Bean B のロックを持っています。しばらくすると、Thread 1Thread 2Bean B を持っているためそれをロックしてブロックしようとします。同様にして Thread 2Thread 1 が A のロックを持っているためそれをロックしてブロックしようとします。この時点で、 両スレッドはデッドロックとなり、 他のスレッドですでにロックされているリソースへのアクセスを待機することになります。
デッドロックの定義例

図29.8 デッドロックの定義例

JBoss のデフォルトとなるロックポリシーは、トランザクションが完了するまでそのトランザクションのコンテキスト内に呼び出しが発生する場合に Entity bean をロックすることです。このため、多くのエンティティ bean にアクセスする長期実行のトランザクションがある場合や、 bean へのアクセス順序に注意を怠った場合にデッドロックは非常に簡単に発生します。デッドロックの問題を回避するためさまざまな技術や詳細設定を使用することができます。これらについては本項で後述します。

29.4.5.1. デッドロックの検出

幸い、JBoss はデッドロックの検出が可能です。JBoss には待機中のトランザクションや、ブロック中のトランザクションに関するグローバルな内部グラフがあります。エンティティ bean ロックを取得できないとスレッドが判断すると必ず、bean 上で現在ロックを保持しているトランザクションを割り出してそれ自体をブロック中のトランザクションのグラフに追加します。グラフの具体例を表29.1「ブロックされているトランザクションテーブルの例」に示しています。

表29.1 ブロックされているトランザクションテーブルの例

ブロックしている TX ロックを保持する TX
Tx1 Tx2
Tx3 Tx4
Tx4 Tx1
スレッドが実際にブロックを行う前に、デッドロックの問題があるかどうかを検出しようとします。検出はブロックトランザクショングラフを検討することによって行われます。グラフを検討するたびにブロックされているトランザクションの記録を残していきます。 グラフ内に複数回にわたりブロックされているノードを検出すると、デッドロックが発生していると認識して ApplicationDeadlockException を送出します。 この例外によりトランザクションのロールバックが行われて、このロールバックによりトランザクションが保持しているすべてのロックが解放されることになります。