【发布时间】:2013-06-16 21:56:01
【问题描述】:
对于 Java 对象,有没有办法告诉哪个线程(或 null)当前拥有它的监视器?或者至少是一种判断当前线程是否拥有它的方法?
【问题讨论】:
-
你可以做一个线程转储来获取这些信息
标签: java multithreading synchronization
对于 Java 对象,有没有办法告诉哪个线程(或 null)当前拥有它的监视器?或者至少是一种判断当前线程是否拥有它的方法?
【问题讨论】:
标签: java multithreading synchronization
java 类监视器是 JVM 内部的,你不能真正使用它。
如果你知道对象被锁定,你可以尝试再次获取监视器 - 如果你能得到它,这意味着你正在从你的线程中锁定对象(因为 java 锁是递归的 - 你可以锁定两次来自同一个线程)。 问题是您无法尝试进行同步。
您可以使用 unsafe 对象来做到这一点。
unsafe 有一个 tryMonintorEnter() 方法可以做到这一点。见unsafe。
Unsafe 可能实际上可以帮助您获取持有监视器的线程,但我不知道该怎么做...
【讨论】:
在 Java 1.6 中,您可以使用反射来获取此信息。
ThreadMXBean tBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfo = tBean .getThreadInfo(bean.getAllThreadIds(), true, true);
【讨论】:
您可能想看看ReentrantLock,而不是使用synchronized,尤其是它的方法getOwner() 和isHeldByCurrentThread()。但是,使用它需要更多的纪律,因为您必须明确地 unlock() 它,最好在 finally 块中。
【讨论】:
synchronized(myLock) { .. } 到 myLock.lock(); try { .. } finally {myLock.unlock();}。不过,与同步锁不同,锁不能是任何对象。
我自己找到了一些答案。测试当前线程是否持有监视器,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() 为 true 的 VM,因此它的可移植性较差。但如果您只想测试当前线程,Thread.holdsLock 效果很好!否则,java.util.concurrent.locks.Lock 的实现可能会提供比普通 Java 监视器更多的信息和灵活性(感谢 @user1252434)。
【讨论】: