簡體   English   中英

多個Java線程似乎鎖定了同一個監視器?

[英]Multiple Java threads seemingly locking same monitor?

在Java threaddump中,我發現了以下內容:

"TP-Processor184" daemon prio=10 tid=0x00007f2a7c056800 nid=0x47e7 waiting for monitor entry [0x00007f2a21278000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getNonVirtualItemState(SharedItemStateManager.java:1725)
    - locked <0x0000000682f99d98> (a org.apache.jackrabbit.core.state.SharedItemStateManager)
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getItemState(SharedItemStateManager.java:257)

"TP-Processor137" daemon prio=10 tid=0x00007f2a7c00f800 nid=0x4131 waiting for monitor entry [0x00007f2a1ace7000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getNonVirtualItemState(SharedItemStateManager.java:1725)
    - locked <0x0000000682f99d98> (a org.apache.jackrabbit.core.state.SharedItemStateManager)
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getItemState(SharedItemStateManager.java:257)

這里的重點是兩個線程都鎖定了監視器<0x0000000682f99d98> (無論它們現在正在等待兩個不同的其他監視器)。

在查看Thread Dump Analyzer時,如果選擇了該監視器,它實際上會在底部顯示“Threads locking monitor:2”,並且“2 Threads s slock”。 有關屏幕截圖,請參閱https://lh4.googleusercontent.com/-fCmlnohVqE0/T1D5lcPerZI/AAAAAAAAD2c/vAHcDiGOoMo/s971/locked_by_two_threads_3.png ,我不允許在此處粘貼圖片。

這是否意味着關於監視器鎖定信息,threaddumps不是原子的? 我無法想象這真的是JVM的鎖定錯誤(1.6.0_26-b03)。

類似的問題已經在幾個線程中被問到可以鎖定Java中的同一個監視器嗎? ,但我的答案並沒有看到多個線程鎖定同一個監視器的真正意義,即使他們可能正在等待其他一些。

2014年5月13日更新:

更新的問題多個線程持有相同的鎖? 有代碼重現行為,@ rssx已根據他的答案提交了一份相應的錯誤報告https://bugs.openjdk.java.net/browse/JDK-8036823

我不認為你的線程轉儲說你的兩個線程是“等待兩個不同的其他監視器”。 我想這是說他們都在同一台顯示器上等待,但是在兩個不同的代碼點。 這可能是堆棧位置或對象實例位置等。 這是一個關於分析堆棧轉儲的好文檔。

幾個線程可以在Java中對同一個監視器進行鎖定嗎?

不會。您的堆棧轉儲顯示在相同代碼位置但在不同堆棧幀中鎖定在同一監視器上的兩個線程 - 或者看起來與操作系統相關的任何值。

編輯:

我不確定為什么線程轉儲似乎是說兩個線程都有一個行被鎖定,因為這似乎只有在它們處於wait()方法時才被允許。 我注意到你鏈接到1.6.5版。 這真的是你正在使用的版本嗎? 在版本2.3.6(可能是最新版本)中, 1725行實際上是一個wait

1722        synchronized (this) {
1723            while (currentlyLoading.contains(id)) {
1724                try {
1725                    wait();
1726                } catch (InterruptedException e) {

即使它是一個獨占的synchronized鎖,你也可以看到這種堆棧跟蹤。 例如,Linux下的以下堆棧轉儲用於從同一代碼行鎖定在同一對象上的兩個線程,但是在Runnable.run()方法的兩個不同實例中。 這是我愚蠢的小測試程序 請注意,監視器條目號是不同的,即使它是相同的鎖和相同的代碼行號。

"Thread-1" prio=10 tid=0x00002aab34055c00 nid=0x4874
  waiting for monitor entry [0x0000000041017000..0x0000000041017d90]
java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00002aab072a1318> (a java.lang.Object)
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38)
    - locked <0x00002aab072a1318> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:619)

"Thread-0" prio=10 tid=0x00002aab34054c00 nid=0x4873
  waiting for monitor entry [0x0000000040f16000..0x0000000040f16d10]
java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00002aab072a1318> (a java.lang.Object)
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38)
    - locked <0x00002aab072a1318> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:619)

在我的Mac上,格式不同,但“監視器條目”之后的數字對於相同的行號不同。

"Thread-2" prio=5 tid=7f8b9c00d000 nid=0x109622000
  waiting for monitor entry [109621000]
java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f3192fb0> (a java.lang.Object)
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38)
    - locked <7f3192fb0> (a java.lang.Object)

"Thread-1" prio=5 tid=7f8b9f80d800 nid=0x10951f000
  waiting for monitor entry [10951e000]
java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f3192fb0> (a java.lang.Object)
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38)
    - locked <7f3192fb0> (a java.lang.Object)

此Oracle文檔將該值描述如下:

地址范圍,它給出了線程有效堆棧區域的估計值

在分析大量競爭鎖時,您可能會遇到JVM中堆棧跟蹤例程中的修飾錯誤 - 它可能與此錯誤相同或不同。

事實是,你的兩個線程都沒有實際設法獲得SharedItemStateManager上的SharedItemStateManager ,正如你可以看到它們正在報告waiting for monitor entry的事實。 錯誤是在兩種情況下進一步向上堆棧跟蹤它們應該報告waiting to lock而不是locked

分析這樣的奇怪堆棧跟蹤時的解決方法是始終檢查聲稱已locked對象的線程是否也在等待獲取對同一對象的鎖定。

(不幸的是,這種分析需要交叉引用堆棧跟蹤中的行號與源代碼,因為waiting for monitor entry頭中的數字與堆棧跟蹤中的locked行之間沒有關系。根據此Oracle文檔 ,行TP-Processor184" daemon prio=10 tid=0x00007f2a7c056800 nid=0x47e7 waiting for monitor entry [0x00007f2a21278000]的數字0x00007f2a21278000 TP-Processor184" daemon prio=10 tid=0x00007f2a7c056800 nid=0x47e7 waiting for monitor entry [0x00007f2a21278000]是指線程的有效堆棧區域的估計 。所以它看起來像一個監視器ID,但它不是' - 你可以看到你給出的兩個線程在堆棧中的不同地址)。

當一個線程鎖定一個對象但是wait()時,另一個線程可以鎖定同一個對象。 您應該能夠看到許多線程“持有”相同的鎖等待。

AFAIK,唯一的另一種情況是當多個線程已經鎖定並等待並准備重新獲取鎖定時,例如在notifyAll()上。 他們不再等待,但在他們再次獲得鎖定之前無法繼續。 (一次只有一個線程可以做到這一點)

"http-0.0.0.0-8080-96" daemon prio=10 tid=0x00002abc000a8800 nid=0x3bc4 waiting for monitor entry [0x0000000050823000]
    java.lang.Thread.State: BLOCKED (on object monitor)
    at org.apache.lucene.search.FieldCacheImpl$Cache.get(FieldCacheImpl.java:195)
    - locked <0x00002aadae12c048> (a java.util.WeakHashMap)

"http-0.0.0.0-8080-289" daemon prio=10 tid=0x00002abc00376800 nid=0x2688 waiting for monitor entry [0x000000005c8e3000]
    java.lang.Thread.State: BLOCKED (on object monitor)
    at org.apache.lucene.search.FieldCacheImpl$Cache.get(FieldCacheImpl.java:195)
    - locked <0x00002aadae12c048> (a java.util.WeakHashMap

"http-0.0.0.0-8080-295" daemon prio=10 tid=0x00002abc00382800 nid=0x268e runnable [0x000000005cee9000]
     java.lang.Thread.State: RUNNABLE
     at org.apache.lucene.search.FieldCacheImpl$Cache.get(FieldCacheImpl.java:195)
     - locked <0x00002aadae12c048> (a java.util.WeakHashMap)

在我們的線程轉儲中,我們有幾個線程鎖定相同的監視器,但只有一個線程可以運行 可能是因為鎖定競爭 ,我們有284個其他線程在等待鎖定。 多個線程持有相同的鎖? 說這只存在於線程轉儲中,因為線程轉儲不是原子操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM