昔、私はJavaリファレンスブックからの文を保存しました:"Javaにはデッドロックを処理するメカニズムがありません。 Java 2nd Edition、p.516)
それで、それは何ですか? Javaでデッドロックのケースをキャッチする方法はありますか?つまり、デッドロックが発生したことをコードが理解する方法はありますか?
JDK 1.5以降、発生するデッドロックを見つけて検査するための_Java.lang.management
_パッケージには非常に便利なメソッドがあります。 ThreadMXBean
クラスのfindMonitorDeadlockedThreads()
およびfindDeadlockedThreads()
メソッドを参照してください。
これを使用する可能性のある方法は、これを行う独立したウォッチドッグスレッド(または定期的なタスク)を持つことです。
サンプルコード:
_ ThreadMXBean tmx = ManagementFactory.getThreadMXBean();
long[] ids = tmx.findDeadlockedThreads();
if (ids != null) {
ThreadInfo[] infos = tmx.getThreadInfo(ids, true, true);
System.out.println("The following threads are deadlocked:");
for (ThreadInfo ti : infos) {
System.out.println(ti);
}
}
_
JConsole は、実行中のアプリケーションのデッドロックを検出できます。
JDK 5および6は、保持されているロック情報をフルスレッドダンプ(kill -3、jstack、jconsoleなどで取得)にダンプします。 JDK 6には、ReentrantLockおよびReentrantReadWriteLockに関する情報も含まれています。この情報から、ロックサイクルを見つけることでデッドロックを診断できます。スレッドAはロック1を保持し、スレッドBはロック2を保持し、Aは2を要求するか、Bは1を要求します。
他の分析ツールは、たとえ発生していなくても潜在的なデッドロックを実際に見つけることができます。 OptimizeIt、JProbe、Coverityなどのベンダーのスレッドツールが最適です。
並行パッケージを使用するデッドロックには、デバッグが非常に難しいタイプがあることに注意してください。 ReentrantReadWriteLockがあり、1つのスレッドが読み取りロックを取得し、(たとえば)書き込みロックの取得を待機している他のスレッドが保持しているモニターに入ろうとします。デバッグを特に難しくしているのは、誰が読み取りロックに入ったかの記録がないことです。それは単なるカウントです。スレッドは例外をスローし、読み取りカウントをゼロ以外のままにしていた可能性もあります。
前述のfindDeadlockedThreadsメソッドが取得できないサンプルデッドロックは次のとおりです。
import Java.util.concurrent.locks.*;
import Java.lang.management.*;
public class LockTest {
static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public static void main(String[] args) throws Exception {
Reader reader = new Reader();
Writer writer = new Writer();
sleep(10);
System.out.println("finding deadlocked threads");
ThreadMXBean tmx = ManagementFactory.getThreadMXBean();
long[] ids = tmx.findDeadlockedThreads();
if (ids != null) {
ThreadInfo[] infos = tmx.getThreadInfo(ids, true, true);
System.out.println("the following threads are deadlocked:");
for (ThreadInfo ti : infos) {
System.out.println(ti);
}
}
System.out.println("finished finding deadlocked threads");
}
static void sleep(int seconds) {
try {
Thread.currentThread().sleep(seconds*1000);
} catch (InterruptedException e) {}
}
static class Reader implements Runnable {
Reader() {
new Thread(this).start();
}
public void run() {
sleep(2);
System.out.println("reader thread getting lock");
lock.readLock().lock();
System.out.println("reader thread got lock");
synchronized (lock) {
System.out.println("reader thread inside monitor!");
lock.readLock().unlock();
}
}
}
static class Writer implements Runnable {
Writer() {
new Thread(this).start();
}
public void run() {
synchronized (lock) {
sleep(4);
System.out.println("writer thread getting lock");
lock.writeLock().lock();
System.out.println("writer thread got lock!");
}
}
}
}
一般的にJavaはデッドロック検出を提供しません。同期キーワードと組み込みモニターにより、明示的なロックのある言語よりもデッドロックについて推論するのが多少難しくなります。
ロックスキームの推論を容易にするために、Java.util.concurrent.Lockロックなどの使用に移行することをお勧めします。実際、デッドロック検出を使用して、ロックインターフェイスの独自の実装を簡単に作成できます。アルゴリズムは、基本的にロック依存関係グラフをトラバースし、サイクルを探すことです。
Java 5を使用している場合、ThreadMXBeanのfindMonitorDeadlockedThreads()
メソッドを呼び出すことができます。これは、Java.lang.management.ManagementFactory.getThreadMXBean()
の呼び出しを介して取得できます。これにより、デッドロックが検出されます。 Java 6では、findDeadlockedThreads()
があります。これは、「所有可能なシンクロナイザー(たとえばReentrandLock
およびReentrantReadWriteLock
)。
これらのメソッドを呼び出すにはおそらく費用がかかるため、トラブルシューティングの目的にのみ使用する必要があることに注意してください。
すべてのスレッドが同じ順序でロックを要求して解放するという単純なルールに従うと、デッドロックを回避できます。この方法では、デッドロックが発生する可能性のある状況に陥ることはありません。
食事の哲学者の問題でさえ、左と右のスプーンの相対的な概念を使用するため、この規則に違反していると見なすことができます。スプーンに一意の番号が付けられ、哲学者全員が最初に最も番号の小さいスプーンを取得しようとした場合、デッドロックは不可能になります。
私の意見では、予防は治療よりも優れています。
これは、スレッドが適切に機能するようにするために私が従うべき2つのガイドラインの1つです。もう1つは、各スレッドがいつでも何をしているかを完全に認識している唯一のスレッドであるため、各スレッドがsolely自身の実行を担当することを保証することです。
つまり、Thread.stop
呼び出し、グローバルフラグ(またはメッセージキューなど)を使用して、アクションを実行する別のスレッドに通知します。次に、そのスレッドに実際の作業を行わせます。
正確にはあなたが尋ねたものではありませんが、デッドロックdoesが発生すると、プロセスIDで「kill -3」を実行でき、スレッドダンプが標準出力にダンプされます。また、1.6 jvmには、GUIの方法で同じことを行ういくつかのツールがあります。
コマンドラインから実行していて、デッドロック状態にあると思われる場合は、ウィンドウでctrl + break(unixではctrl + \)を試してスレッドダンプを取得してください。 http://Java.Sun.com/javase/6/webnotes/trouble/TSG-VM/html/gbmps.html を参照してください
Javaはデッドロックを検出できます(実行時ではありませんが、診断および報告できます)。
たとえば、「Saurabh M. Chande」のコードを少し修正したバージョンを使用する場合(Javaに変更し、各実行でロックを保証するためにタイミングを追加します)。次のように入力すると、デッドロックします。
kill -3 PID # where 'PID' is the Linux process ID
次の情報を含むスタックダンプを生成します。
Found one Java-level deadlock:
=============================
"Thread-0":
waiting to lock monitor 0x08081670 (object 0x7f61ddb8, a Deadlock$A),
which is held by "main"
"main":
waiting to lock monitor 0x080809f0 (object 0x7f61f3b0, a Deadlock$B),
which is held by "Thread-0"
JavaSpecialistsのDr. Heinz Kabutzは、楽しく有益な Java deadlocks に関するニュースレターの問題を書いており、ThreadMXBeanと呼ばれるものを 別のニュースレターの問題 これらの間で、問題についての良いアイデアと、独自の計測を行うためのいくつかの指針を得る必要があります。
Eclipseでデバッグしている場合は、アプリケーションを一時停止して(デバッグビューでアプリを選択し、デバッグツールバーの小さな||ボタンを押す)、デッドロックを報告できます。
例については、 http://runnerwhocodes.blogspot.com/2007/10/deadlock-detection-with-Eclipse.html を参照してください。
Java 5では、スレッドのさまざまな監視方法を提供するインターフェイスであるThreadMXBeanが導入されました。 ...違いは、findDeadlockedThreadsは所有者ロック(Java.util.concurrent)によるデッドロックも検出できるのに対し、findMonitorDeadlockedThreadsはモニターロック(同期ブロック)のみを検出できることです。
または、プログラムで検出することもできます。これを参照してください https://dzone.com/articles/how-detect-Java-deadlocks