对于Java对象,有没有办法告诉哪个Thread(或null)当前拥有其监视器?或者至少一种方法来判断当前线程是否拥有它?
答案 0 :(得分:9)
Thread.holdsLock
存在!
if (!Thread.holdsLock(data)) {
throw new RuntimeException(); // complain
}
这非常快(亚微秒),自1.4以来一直可用。
为了测试一般情况下,哪个线程(或线程ID)持有锁,可以使用java.lang.management
类来执行此操作(感谢@amicngh)。
public static long getMonitorOwner(Object obj) {
if (Thread.holdsLock(obj)) return Thread.currentThread().getId();
for (java.lang.management.ThreadInfo ti :
java.lang.management.ManagementFactory.getThreadMXBean()
.dumpAllThreads(true, false)) {
for (java.lang.management.MonitorInfo mi : ti.getLockedMonitors()) {
if (mi.getIdentityHashCode() == System.identityHashCode(obj)) {
return ti.getThreadId();
}
}
}
return 0;
}
有一些警告:
ThreadMXBean.isObjectMonitorUsageSupported()
为真的VM,因此它的可移植性较差。但是如果你只想测试当前的线程,Thread.holdsLock
效果很好!否则,java.util.concurrent.locks.Lock
的实现可能提供比普通Java监视器更多的信息和灵活性(感谢@ user1252434)。
答案 1 :(得分:2)
java类监视器是JVM的内部监视器,你无法真正使用它。
如果您知道对象已被锁定,您可以尝试再次获取监视器 - 如果您可以获取它,则意味着您正在从线程锁定对象(因为java锁是递归的 - 您可以锁定两次来自同一个线程)。 问题是您无法尝试进行同步。
您可以使用不安全对象来执行此操作。
unsafe有一个tryMonintorEnter()
方法可以做到这一点。见unsafe。
不安全可能真的可以帮助你获得持有显示器的线程,但我不知道该怎么做......
答案 2 :(得分:1)
在 Java 1.6 中,您可以使用Reflection获取此信息。
ThreadMXBean tBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfo = tBean .getThreadInfo(bean.getAllThreadIds(), true, true);
答案 3 :(得分:1)
您可能希望查看ReentrantLock,而不是使用synchronized
,尤其是方法getOwner()
和isHeldByCurrentThread()
。但是,使用它需要更多的纪律,因为你明确地需要unlock()
它,最好是在finally
块中。