真是个好问题,我们绝对可以使用Thread.holdLocks(obj),它确实很有用,但有一个限制,我们只能知道当前线程是否对传递的对象持有锁。但是根据问题,我们希望有一些机制,以便我们可以找到哪个线程(如果有的话)在给定对象上持有锁。
目前我能想到以下两种方式:
- jconsole
jdk 的 bin 目录中有一个 jconsole 实用程序。我们可以获得有关线程及其状态(WAITING、Blocked 等)的信息。下面是例子:
假设我们有以下类:
public class ThreadLockTest {
private int i = 11;
public static void main(String[] args) {
ThreadLockTest obj = new ThreadLockTest();
TestRunner runner = new TestRunner(obj);
Thread t1 = new Thread(runner, "t1");
Thread t2 = new Thread(runner, "t2");
t1.start();
t2.start();
}
public synchronized int getI() {
try {
System.out.println(Thread.currentThread().getName()+" starting wait");
for(;;) {
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return i;
}
public synchronized void setI(int i) {
this.i = i;
}
private static class TestRunner implements Runnable {
private ThreadLockTest obj;
private TestRunner(ThreadLockTest obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println("i: "+obj.getI());
}
}
}
运行上面的程序,然后打开jconsole,连接到你的程序进程。现在看下面的 jconsole 截图,在我的例子中,线程“t1”正在持有锁,线程“t2”正在等待它。您可以在 jconsole 中看到消息,它清楚地显示了哪个线程正在等待哪个锁,以及哪个线程拥有该锁。您甚至可以使用 jconsole 来检测死锁(如果有的话)。
在下面的屏幕截图中,您可以看到消息清楚地表明,线程 t2 被线程 t1 拥有的锁阻塞。
- 维护对象-线程映射:
在这里,我们可以维护一个
public synchronized void anyMethod() {
MAP.put(this,Thread.currentThread());
.................
................
Map.remove(this);
}
我知道这种方法有很多缺点,但是如果我们真的需要知道在任何对象上持有锁的线程并且我们不想使用 jconsole,我们可以考虑类似这种方法。我知道这种方法会使代码变脏。所以尽量避免它,只使用 jconsole 来检查线程状态,甚至检测死锁,如果有的话。
如果您确实需要了解哪些线程在哪些锁上被阻塞,我强烈建议您使用 jconsole。