【问题标题】:Determine which thread owns a monitor确定哪个线程拥有监视器
【发布时间】:2013-06-16 21:56:01
【问题描述】:

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

【问题讨论】:

  • 你可以做一个线程转储来获取这些信息

标签: java multithreading synchronization


【解决方案1】:

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

如果你知道对象被锁定,你可以尝试再次获取监视器 - 如果你能得到它,这意味着你正在从你的线程中锁定对象(因为 java 锁是递归的 - 你可以锁定两次来自同一个线程)。 问题是您无法尝试进行同步。

您可以使用 unsafe 对象来做到这一点。 unsafe 有一个 tryMonintorEnter() 方法可以做到这一点。见unsafe

Unsafe 可能实际上可以帮助您获取持有监视器的线程,但我不知道该怎么做...

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 我不熟悉 RentrantLock。虽然这不是我的问题,但我认为这实际上对我的用例更好,因为我可以在 C 类中进行锁定并在调用之间保持锁定。非常感谢。
      • 如果你愿意,你可以保留你的锁定逻辑。使用 ReentrantLock 唯一需要的更改是从 synchronized(myLock) { .. }myLock.lock(); try { .. } finally {myLock.unlock();}。不过,与同步锁不同,锁不能是任何对象。
      【解决方案4】:

      我自己找到了一些答案。测试当前线程是否持有监视器,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. 它有点慢(在我的情况下约为 ½ 毫秒,并且可能随着线程数线性增加)。
      2. 它需要 Java 1.6 和一个 ThreadMXBean.isObjectMonitorUsageSupported() 为 true 的 VM,因此它的可移植性较差。
      3. 它需要“监控”安全权限,因此可能无法在沙盒小程序中运行。
      4. 如果需要,将线程 ID 转换为 Thread 对象有点不重要,因为我想您必须使用 Thread.enumerate 然后循环找出哪个具有 ID,但是这具有理论上的竞争条件,因为当您调用 enumerate 时,该线程可能不再存在,或者可能出现了具有相同 ID 的新线程。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-01
        • 1970-01-01
        相关资源
        最近更新 更多