确定哪个线程拥有监视器

对于Java对象,有没有办法告诉哪个Thread(或null)当前拥有其监视器? 或者至少一种方法来判断当前线程是否拥有它?

我自己找到了一些答案。 要测试当前线程是否包含监视器, 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; } 

这有几点需要注意:

  1. 它有点慢(在我的情况下约为1/2毫秒,并且可能与线程数呈线性增加)。
  2. 它需要Java 1.6,以及ThreadMXBean.isObjectMonitorUsageSupported()为true的VM,因此它的可移植性较低。
  3. 它需要“监视器”安全权限,因此可能无法使用沙盒applet。
  4. 如果需要,将线程ID转换为Thread对象有点不重要,因为我想你必须使用Thread.enumerate然后循环查找哪个有ID,但这有理论竞争条件,因为在您调用enumerate时,该线程可能不再存在,或者可能出现具有相同ID的新线程。

但是如果你只想测试当前的线程, Thread.holdsLock效果很好! 否则, java.util.concurrent.locks.Lock实现可以提供比普通Java监视器更多的信息和灵活性(感谢@ user1252434)。

java类监视器是JVM的内部监视器,你无法真正使用它。

如果您知道对象已被锁定,您可以尝试再次获取监视器 – 如果您可以获取它,则意味着您正在从线程锁定对象(因为java锁是递归的 – 您可以从同一个锁定两次线)。 问题是你无法尝试同步。

您可以使用不安全的对象来执行此操作。 unsafe有一个tryMonintorEnter()方法就是tryMonintorEnter() 。 看不安全 。

不安全的可能实际上可以帮助你获得持有显示器的线程,但我不知道如何做到这一点……

Java 1.6中,您可以使用Reflection来获取此信息。

 ThreadMXBean tBean = ManagementFactory.getThreadMXBean(); ThreadInfo[] threadInfo = tBean .getThreadInfo(bean.getAllThreadIds(), true, true); 

您可能希望查看ReentrantLock ,而不是使用synchronized ,尤其是其方法getOwner()isHeldByCurrentThread() 。 但是,使用它需要更多的纪律,因为你明确地必须unlock()它,最好是在finally块中。