2013-06-20 20 views
7

有沒有辦法告訴Java對象,哪個線程(或null)當前擁有它的監視器?或者至少有一種方法來判斷當前線程是否擁有它?確定哪個線程擁有監視器

+0

您可以通過線程轉儲獲取此信息 – fge

回答

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; 
} 

有跟這個有幾個注意事項:

  1. 這是一個有點慢(〜½毫秒在我的情況大概與線程的數量線性增加)。
  2. 它需要Java 1.6和一個虛擬機ThreadMXBean.isObjectMonitorUsageSupported()爲真,因此它的便攜性較差。
  3. 它需要「監視器」安全權限,因此可能不適用於沙盒applet。
  4. 如果需要,將線程ID轉換爲線程對象,這有點不重要,因爲我想你必須使用Thread.enumerate,然後循環找出哪一個具有ID,但是這具有理論上的競爭條件,因爲當你調用枚舉時,該線程可能不再存在,或者可能出現了具有相同ID的新線程。

但是,如果您只想測試當前線程,Thread.holdsLock工作得很好!否則,java.util.concurrent.locks.Lock的實現可能比普通的Java監視器提供更多的信息和靈活性(謝謝@ user1252434)。

2

java類監視器是JVM的內部,你不能真正玩它。

如果您知道該對象被鎖定,您可以嘗試再次獲取監視器 - 如果能夠得到它,這意味着您正在鎖定線程中的對象(因爲java鎖是遞歸的 - 您可以鎖定兩次來自同一個線程)。 問題是你不能嘗試來同步。

您可以使用不安全的對象來做到這一點。 不安全有一個tryMonintorEnter()方法可以做到這一點。見unsafe

不安全也許能助您獲得持有監視器的線程,但我不知道該怎麼做......

1

的Java 1.6你可以使用反射來得到這個信息。

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

而不是使用​​的,你可能想看看ReentrantLock,尤其是它的方法getOwner()isHeldByCurrentThread()。然而,使用它需要更多的訓練,因爲您明確地必須unlock()它,最好是在finally塊。

+0

我對RentrantLock並不熟悉。雖然這不是我的問題,但我認爲它對我的用例來說更好,因爲我可以在類C中進行鎖定並保持通話之間的鎖定。非常感謝。 – Boann

+0

如果你喜歡,你可以保留你的鎖定邏輯。使用ReentrantLock所需的唯一更改是從'synchronized(myLock){..}'到'myLock.lock();嘗試{..}終於{myLock.unlock();}'。雖然,與同步不同,鎖不能只是任何對象。 – user1252434

相關問題