Java プログラムでデッドロックが発生したことをプログラムで検出するにはどうすればよいですか?
9 に答える
ThreadMXBean
これは、JDK に同梱されているを使用してプログラムで実行できます。
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] threadIds = bean.findDeadlockedThreads(); // Returns null if no threads are deadlocked.
if (threadIds != null) {
ThreadInfo[] infos = bean.getThreadInfo(threadIds);
for (ThreadInfo info : infos) {
StackTraceElement[] stack = info.getStackTrace();
// Log or store stack trace information.
}
}
明らかに、このデッドロック チェックを実行しているスレッドを分離する必要があります。そうしないと、そのスレッドがデッドロックすると、チェックを実行できなくなります。
ちなみに、これは JConsole が内部で使用しているものです。
調査に役立つ 1 つのヒント:
アプリケーションのレッドハンドをキャッチでき、デッドロックが発生した疑いがある場合は、java.exe コンソール ウィンドウで「Ctrl-Break」(Solaris/Linux では「Ctrl-\」) を押します。jvm は、すべてのスレッドの現在のステータスとスタック トレースをダンプし、デッド ロックを見つけて正確に説明します。
次のようになります。
Full thread dump Java HotSpot(TM) Client VM (1.5.0_09-b03 mixed mode):
"[Test Timer] Request Queue" prio=6 tid=0x13d708d0 nid=0x1ec in Object.
wait() [0x1b00f000..0x1b00fb68]
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at library.util.AsyncQueue.run(AsyncQueue.java:138)
- locked <0x02e70000> (a test.server.scheduler.SchedulerRequestQueue)
...
Found one Java-level deadlock:
=============================
"Corba service":
waiting to lock monitor 0x13c06684 (object 0x04697d90, a java.lang.Object),
which is held by "[Server Connection] Heartbeat Timer"
"[Server Connection] Heartbeat Timer":
waiting to lock monitor 0x13c065c4 (object 0x0467e728, a test.proxy.ServerProxy), which is held by "Corba service"
Java stack information for the threads listed above:
===================================================
"Corba service":
at test.proxy.ServerProxy.stopHBWatchDog(ServerProxy:695)
- waiting to lock <0x04697d90> (a java.lang.Object)
...
JArmusは、デッドロックの検出と回避のためのライブラリです。Thread.join
、CyclicBarrier
、CountDownLatch
、Phaser
、および
のサポートが含まれます
ReentrantLock
。
JArmus を使用するには、コードを計測する必要があります。インストルメント化されたクラスの 1 つを介して、または JArmus インストルメンターを使用して自動的にjarmusc
。
java -jar jarmusc.jar yourprogram.jar checkedprogram.jar
入力yourprogram.jar
はチェックしたいプログラムです。出力は、デッドロックを自動的に検出するためのチェックを含む同じプログラムです。
障壁には助けが必要です
CyclicBarrier
クラス、CountDownLatch
でデッドロックを検証するPhaser
のは少し難しいです --- たとえば、JConsole はこれらのタイプのデッドロックを検出できません。JArmus はあなたの助けを必要としています。どのスレッドが同期に影響を与えているかを指定する必要があります。これらを登録済みスレッドと呼びます。
できるだけ早く、スレッドは自分自身を登録済みとしてマークする必要があります。登録されたスレッドをマークするのに適した場所は、最初のメソッドRunnable.run
です。
JArmus.register(latch);
例
デッドロックする次のプログラムは、JArmus によって正しく識別されます。
final CountDownLatch latch = new CountDownLatch(2);
final CyclicBarrier barrier = new CyclicBarrier(2);
final Queue<Exception> exceptions = new ArrayDeque<>();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
JArmus.register(barrier); // do not forget to register!
JArmus.register(latch); // do not forget to register!
latch.countDown();
latch.await();
barrier.await();
} catch (Exception e) {
exceptions.add(e);
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
JArmus.register(barrier); // do not forget to register!
JArmus.register(latch); // do not forget to register!
barrier.await();
latch.countDown();
latch.await();
} catch (Exception e) {
exceptions.add(e);
}
}
});
t1.start();
t2.start();
IBM の MTRATを検討することをお勧めします。結局のところ、予防は治療よりも優れています。マルチコア ソフトウェア開発キットには、デッドロック検出ツールも付属しています。
プログラムによる検出が必要ない場合は、JConsoleを介してこれを行うことができます。スレッドタブには、「デッドロックの検出」ボタンがあります。JDK6 では、これにより組み込みモニターとj.u.c
Lock
s の両方のロックが検出されます。
$JAVA_HOM/bin/jconsole
コマンドを使用して JConsole を実行します。
ここにコードがあります: http://www.java2s.com/Code/Java/Development-Class/JavalangmanagementAPI.htmを使用してアプリケーション内でプログラム的にデッドロック検出を実行する
魔法が起こるThreadMonitor.findDeadlock()
:
public boolean findDeadlock() {
long[] tids;
if (findDeadlocksMethodName.equals("findDeadlockedThreads")
&& tmbean.isSynchronizerUsageSupported()) {
tids = tmbean.findDeadlockedThreads();
if (tids == null) {
return false;
}
System.out.println("Deadlock found :-");
ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true);
for (ThreadInfo ti : infos) {
printThreadInfo(ti);
printLockInfo(ti.getLockedSynchronizers());
System.out.println();
}
} else {
tids = tmbean.findMonitorDeadlockedThreads();
if (tids == null) {
return false;
}
ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
for (ThreadInfo ti : infos) {
// print thread information
printThreadInfo(ti);
}
}
return true;
}
ThreadMXBean
これは、 Java 5 と 6 で異なる名前を持つの API を呼び出します(したがって、 outer if()
)。
コード例ではロックを中断することもできるため、デッドロックを解消することもできます。
tempus-fugitは、プログラムによるスレッド ダンプ クラスと共にそれを実装しています。上記の mbean メカニズムを使用して実装され、すぐに使用できるドロップインの超大型ソリューションを提供します。
実行時に実行したい場合は、ウォッチドッグを使用できます。