Java 5引入了ThreadMXBean-一个为线程提供各种监视方法的接口。...区别在于findDeadlockedThreads也可以检测到由所有者锁引起的死锁(java.util.concurrent),而findMonitorDeadlockedThreads只能检测到监视器锁(即同步块)
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
class Shared {
synchronized void methodOne(Shared s) {
Thread t = Thread.currentThread();
System.out.println(t.getName() + "is executing methodOne...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName() + "is calling methodTwo...");
s.methodTwo(this);
System.out.println(t.getName() + "is finished executing methodOne...");
}
synchronized void methodTwo(Shared s) {
Thread t = Thread.currentThread();
System.out.println(t.getName() + "is executing methodTwo...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName() + "is calling methodOne...");
s.methodOne(this);
System.out.println(t.getName() + "is finished executing methodTwo...");
}
}
public class ThreadsInJava {
public static void main(String[] args) {
final Shared s1 = new Shared();
final Shared s2 = new Shared();
Thread t1 = new Thread() {
public void run() {
s1.methodOne(s2);
}
};
Thread t2 = new Thread() {
@Override
public void run() {
s2.methodTwo(s1);
}
};
t1.start();
t2.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long ids[] = bean.findMonitorDeadlockedThreads();
if (ids != null) {
ThreadInfo threadInfo[] = bean.getThreadInfo(ids);
for (ThreadInfo threadInfo1 : threadInfo) {
System.out.println("ID of deadlocked thread : " + threadInfo1.getThreadId()); // Prints the ID of
// deadlocked thread
System.out.println("name of deadlocked thread : " + threadInfo1.getThreadName()); // Prints the name of
// deadlocked thread
System.out.println("object : " + threadInfo1.getLockName()); // Prints the string representation of an
// object for
// which thread has entered into deadlock.
System.out.println("ID of thread which currently owns : " + threadInfo1.getLockOwnerId()); // Prints the
// ID of
// thread
// which
// currently
// owns the
// object lock
System.out.println("name of thread which currently owns : " + threadInfo1.getLockOwnerName()); // Prints
// name
// of
// the
// thread
// which
// currently
// owns
// the object lock.
}
} else {
System.out.println("No Deadlocked Threads");
}
}
}
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
public class ThreadDeadlock {
public static void main(String[] args) throws InterruptedException {
Object obj1 = new Object();
Object obj2 = new Object();
Object obj3 = new Object();
Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1");
Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2");
Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3");
t1.start();
Thread.sleep(5000);
t2.start();
Thread.sleep(5000);
t3.start();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long ids[] = bean.findMonitorDeadlockedThreads();
if (ids != null) {
ThreadInfo threadInfo[] = bean.getThreadInfo(ids);
for (ThreadInfo threadInfo1 : threadInfo) {
System.out.println("ID of deadlocked thread : " + threadInfo1.getThreadId()); // Prints the ID of
// deadlocked thread
System.out.println("name of deadlocked thread : " + threadInfo1.getThreadName()); // Prints the name of
// deadlocked thread
System.out.println("object : " + threadInfo1.getLockName()); // Prints the string representation of an
// object for
// which thread has entered into deadlock.
System.out.println("ID of thread which currently owns : " + threadInfo1.getLockOwnerId()); // Prints the
// ID of
// thread
// which
// currently
// owns the
// object lock
System.out.println("name of thread which currently owns : " + threadInfo1.getLockOwnerName()); // Prints
// name
// of
// the
// thread
// which
// currently
// owns
// the object lock.
}
} else {
System.out.println("No Deadlocked Threads");
}
}
}
class SyncThread implements Runnable {
private Object obj1;
private Object obj2;
public SyncThread(Object o1, Object o2) {
this.obj1 = o1;
this.obj2 = o2;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + " acquiring lock on " + obj1);
synchronized (obj1) {
System.out.println(name + " acquired lock on " + obj1);
work();
System.out.println(name + " acquiring lock on " + obj2);
synchronized (obj2) {
System.out.println(name + " acquired lock on " + obj2);
work();
}
System.out.println(name + " released lock on " + obj2);
}
System.out.println(name + " released lock on " + obj1);
System.out.println(name + " finished execution.");
}
private void work() {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.example.thread.deadlock.lock;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BankAccount {
double balance;
final int id;
final Lock lock = new ReentrantLock();
BankAccount(int id, double balance) {
this.id = id;
this.balance = balance;
}
void withdraw(double amount) {
// Wait to simulate io like database access ...
try {
Thread.sleep(10l);
} catch (InterruptedException e) {
}
balance -= amount;
}
void deposit(double amount) {
// Wait to simulate io like database access ...
try {
Thread.sleep(10l);
} catch (InterruptedException e) {
}
balance += amount;
}
static void transfer(BankAccount from, BankAccount to, double amount) {
from.lock.lock();
from.withdraw(amount);
to.lock.lock();
to.deposit(amount);
to.lock.unlock();
from.lock.unlock();
}
public static void main(String[] args) {
final BankAccount fooAccount = new BankAccount(1, 100d);
final BankAccount barAccount = new BankAccount(2, 100d);
new Thread() {
public void run() {
System.out.println(this.getId()+this.getName()+":"+fooAccount.balance);
System.out.println(this.getId()+this.getName()+":"+barAccount.balance);
BankAccount.transfer(fooAccount, barAccount, 10d);
System.out.println(this.getId()+this.getName()+":"+fooAccount.balance);
System.out.println(this.getId()+this.getName()+":"+barAccount.balance);
}
}.start();
new Thread() {
public void run() {
System.out.println(this.getId() + this.getName() + ":" + fooAccount.balance);
System.out.println(this.getId() + this.getName() + ":" + barAccount.balance);
BankAccount.transfer(barAccount, fooAccount, 10d);
System.out.println(this.getId() + this.getName() + ":" + fooAccount.balance);
System.out.println(this.getId() + this.getName() + ":" + barAccount.balance);
}
}.start();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long ids[] = bean.findDeadlockedThreads();
if (ids != null) {
ThreadInfo threadInfo[] = bean.getThreadInfo(ids);
for (ThreadInfo threadInfo1 : threadInfo) {
System.out.println("ID of deadlocked thread : " + threadInfo1.getThreadId()); // Prints the ID of
// deadlocked thread
System.out.println("name of deadlocked thread : " + threadInfo1.getThreadName()); // Prints the name of
// deadlocked thread
System.out.println("object : " + threadInfo1.getLockName()); // Prints the string representation of an
// object for
// which thread has entered into deadlock.
System.out.println("ID of thread which currently owns : " + threadInfo1.getLockOwnerId()); // Prints the
// ID of
// thread
// which
// currently
// owns the
// object lock
System.out.println("name of thread which currently owns : " + threadInfo1.getLockOwnerName()); // Prints
// name
// of
// the
// thread
// which
// currently
// owns
// the object lock.
}
} else {
System.out.println("No Deadlocked Threads");
}
}
}
Java级别监视器死锁曾经很难找到。然后出现了JDK 1.4,并在CTRL + Break中显示了它们。在JDK 5中,我们看到了ThreadMXBean的添加,这使得可以连续监视应用程序中的死锁。但是,局限性在于ThreadMXBean仅适用于同步块,而不适用于新的java.util.concurrent机制。在此时事通讯中,我们重新审视了死锁检测器,并显示了需要进行哪些更改才能使其在JDK 6下工作。此外,我们还了解了什么是异步异常,以及如何将其发布到另一个线程。
在第93号通讯中,我介绍了一个可自动检测线程死锁的类。Bruce Eckel指出,此机制仅适用于监视器 锁(即同步),而不适用于java.util.concurrent 拥有的锁。
在Java 6(测试版2)中,发现了监视器锁和拥有锁的死锁 。但是,需要修改死锁检测器,以获取已死锁的 拥有的锁。
在Java 5中,ThreadMXBean仅具有findMonitorDeadlockedThreads()方法,该方法发现了由synchronized
关键字引起的死锁。现在,我们还有findDeadlockedThreads()
Java虚拟机支持监视可拥有的同步器使用情况时启用的方法。(即新锁或相关构造)
如果您使用的是Java 5,则可以findMonitorDeadlockedThreads()
在ThreadMXBean上调用方法,可以通过调用来获得java.lang.management.ManagementFactory.getThreadMXBean()
。这将发现仅由对象监视器引起的死锁。在Java 6上findDeadlockedThreads()
,还会发现“拥有的同步器(例如ReentrandLock
和ReentrantReadWriteLock
)引起的死锁。
请注意,调用这些方法可能会很昂贵,因此应仅将它们用于故障排除。
从Java 1.8开始,您可以通过jcmd
在终端上使用命令轻松找到程序是否出现死锁。
jcmd
在您的终端上运行:它列出了所有使用Java的程序(PID和名称)。- 现在,运行
jcmd <PID> Thread.print
:这将在控制台上打印线程转储,并且在程序出现死锁时也将打印。
您可以使用jcmd
命令列出的更多选项 来分析Java程序jcmd <PID> help
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"