简体   繁体   English

多个Java线程似乎锁定了同一个监视器?

[英]Multiple Java threads seemingly locking same monitor?

In a Java threaddump I found the following: 在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)

The point here being that both threads have locked monitor <0x0000000682f99d98> (regardless of them now waiting for two different other monitors). 这里的重点是两个线程都锁定了监视器<0x0000000682f99d98> (无论它们现在正在等待两个不同的其他监视器)。

When looking at Thread Dump Analyzer, with that monitor being selected, it really says "Threads locking monitor: 2" at the bottom, and "2 Thread(s) locking". 在查看Thread Dump Analyzer时,如果选择了该监视器,它实际上会在底部显示“Threads locking monitor:2”,并且“2 Threads s slock”。 Please see https://lh4.googleusercontent.com/-fCmlnohVqE0/T1D5lcPerZI/AAAAAAAAD2c/vAHcDiGOoMo/s971/locked_by_two_threads_3.png for the screenshot, I'm not allowed to paste images here. 有关屏幕截图,请参阅https://lh4.googleusercontent.com/-fCmlnohVqE0/T1D5lcPerZI/AAAAAAAAD2c/vAHcDiGOoMo/s971/locked_by_two_threads_3.png ,我不允许在此处粘贴图片。

Does this mean threaddumps aren't atomic with respect to monitor lock information? 这是否意味着关于监视器锁定信息,threaddumps不是原子的? I can't imagine this really being a locking bug of the JVM (1.6.0_26-b03). 我无法想象这真的是JVM的锁定错误(1.6.0_26-b03)。

A similar question has already been asked in Can several threads hold a lock on the same monitor in Java? 类似的问题已经在几个线程中被问到可以锁定Java中的同一个监视器吗? , but the answer to me didn't see the real point of multiple threads locking the same monitor, even though they may be waiting for some other. ,但我的答案并没有看到多个线程锁定同一个监视器的真正意义,即使他们可能正在等待其他一些。

Update May 13th 2014: 2014年5月13日更新:

Newer question Multiple threads hold the same lock? 更新的问题多个线程持有相同的锁? has code to reproduce the behaviour, and @rsxg has filed an according bug report https://bugs.openjdk.java.net/browse/JDK-8036823 along the lines of his answer here. 有代码重现行为,@ rssx已根据他的答案提交了一份相应的错误报告https://bugs.openjdk.java.net/browse/JDK-8036823

I don't think that your thread dump is saying that your two threads are "waiting for two different other monitors". 我不认为你的线程转储说你的两个线程是“等待两个不同的其他监视器”。 I think it is saying that they are both waiting on the same monitor but at two different code points. 我想这是说他们都在同一台显示器上等待,但是在两个不同的代码点。 That may be a stack location or an object instance location or something. 这可能是堆栈位置或对象实例位置等。 This is a great document about analyzing the stack dumps . 这是一个关于分析堆栈转储的好文档。

Can several threads hold a lock on the same monitor in Java? 几个线程可以在Java中对同一个监视器进行锁定吗?

No. Your stack dump is showing two threads locked on the same monitor at the same code location but in different stack frames -- or whatever that value is which seems OS dependent. 不会。您的堆栈转储显示在相同代码位置但在不同堆栈帧中锁定在同一监视器上的两个线程 - 或者看起来与操作系统相关的任何值。

Edit: 编辑:

I'm not sure why the thread dump seems to be saying that both threads have a line locked since that seems to only be allowed if they are in a wait() method. 我不确定为什么线程转储似乎是说两个线程都有一个行被锁定,因为这似乎只有在它们处于wait()方法时才被允许。 I noticed that you are linking to version 1.6.5. 我注意到你链接到1.6.5版。 Is that really the version you are using? 这真的是你正在使用的版本吗? In version 2.3.6 (which may be the latest), the 1725 line actually is a wait . 在版本2.3.6(可能是最新版本)中, 1725行实际上是一个wait

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

You could also see this sort of stack trace even if it was an exclusive synchronized lock. 即使它是一个独占的synchronized锁,你也可以看到这种堆栈跟踪。 For example, the following stack dump under Linux is for two threads locked on the same object from the same code line but in two different instances of the Runnable.run() method. 例如,Linux下的以下堆栈转储用于从同一代码行锁定在同一对象上的两个线程,但是在Runnable.run()方法的两个不同实例中。 Here's my stupid little test program . 这是我愚蠢的小测试程序 Notice that the monitor entry numbers are different, even thought it is the same lock and same code line number. 请注意,监视器条目号是不同的,即使它是相同的锁和相同的代码行号。

"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)

On my Mac, the format is different but again the number after the "monitor entry" is not the same for the same line number. 在我的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)

This Oracle document describe that value as the following: 此Oracle文档将该值描述如下:

Address range, which gives an estimate of the valid stack region for the thread 地址范围,它给出了线程有效堆栈区域的估计值

You are probably running into a cosmetic bug in the stack trace routines in the JVM when analyzing heavily contended locks - it may or may not be the same as this bug . 在分析大量竞争锁时,您可能会遇到JVM中堆栈跟踪例程中的修饰错误 - 它可能与此错误相同或不同。

The fact is that neither of your two threads have actually managed to acquire the lock on the SharedItemStateManager , as you can see from the fact that they are reporting waiting for monitor entry . 事实是,你的两个线程都没有实际设法获得SharedItemStateManager上的SharedItemStateManager ,正如你可以看到它们正在报告waiting for monitor entry的事实。 The bug is that further up in the stack trace in both cases they should report waiting to lock instead of locked . 错误是在两种情况下进一步向上堆栈跟踪它们应该报告waiting to lock而不是locked

The workaround when analyzing strange stack traces like this is to always check that a thread claiming to have locked an object is not also waiting to acquire a lock on the same object. 分析这样的奇怪堆栈跟踪时的解决方法是始终检查声称已locked对象的线程是否也在等待获取对同一对象的锁定。

(Unfortunately this analysis requires cross-referencing the line numbers in the stack trace with the source, code since there is no relationship between the figures in the waiting for monitor entry header and the locked line in the stack trace. As per this Oracle document , the number 0x00007f2a21278000 in the line TP-Processor184" daemon prio=10 tid=0x00007f2a7c056800 nid=0x47e7 waiting for monitor entry [0x00007f2a21278000] refers to an estimate of the valid stack region for the thread . So it looks like a monitor ID but it isn't - and you can see that the two threads you gave are at different addresses in the stack). (不幸的是,这种分析需要交叉引用堆栈跟踪中的行号与源代码,因为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,但它不是' - 你可以看到你给出的两个线程在堆栈中的不同地址)。

When a thread locks an object but wait()s another thread can lock the same object. 当一个线程锁定一个对象但是wait()时,另一个线程可以锁定同一个对象。 You should be able to see a number of threads "holding" the same lock all waiting. 您应该能够看到许多线程“持有”相同的锁等待。

AFAIK, the only other occasion is when multiple threads have locked and waited and are ready to re-acquire the the lock eg on a notifyAll(). AFAIK,唯一的另一种情况是当多个线程已经锁定并等待并准备重新获取锁定时,例如在notifyAll()上。 They are not waiting any more but cannot continue until they have obtained the lock again. 他们不再等待,但在他们再次获得锁定之前无法继续。 (only one thread at a time time can do this) (一次只有一个线程可以做到这一点)

"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)

In our thread dump, we have several threads lock same monitor, but only one thread is runnable . 在我们的线程转储中,我们有几个线程锁定相同的监视器,但只有一个线程可以运行 It probably because of lock competition , we have 284 other threads waiting for the lock. 可能是因为锁定竞争 ,我们有284个其他线程在等待锁定。 Multiple threads hold the same lock? 多个线程持有相同的锁? said this only exists in the thread dump, for thread dump is not atomic operation. 说这只存在于线程转储中,因为线程转储不是原子操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM