Несколько потоков Java, казалось бы, блокируют один и тот же монитор? - PullRequest
11 голосов
/ 02 марта 2012

В потоке Java-дамп я обнаружил следующее:

"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> (независимо от того, что они теперь ждут двух разных другихмониторы).

При просмотре анализатора дампа потоков, когда выбран этот монитор, на самом деле он говорит: «Монитор блокировки потоков: 2» внизу и «Блокировка 2 потоков».Пожалуйста, смотрите https://lh4.googleusercontent.com/-fCmlnohVqE0/T1D5lcPerZI/AAAAAAAAD2c/vAHcDiGOoMo/s971/locked_by_two_threads_3.png для скриншота, мне не разрешено вставлять изображения сюда.

Означает ли это, что потоки данных не являются атомарными в отношении информации о блокировке монитора?Я не могу себе представить, что это действительно ошибка блокировки JVM (1.6.0_26-b03).

Подобный вопрос уже задавался в Может ли несколько потоков удерживать блокировку на одном мониторе вJava? , но ответ на мой вопрос не видел реальной точки зрения нескольких потоков, блокирующих один и тот же монитор, хотя они могут ожидать какого-то другого.

Обновление от 13 мая 2014 года:

Более новый вопрос Несколько потоков содержат одну и ту же блокировку? имеет код для воспроизведения поведения, а @rsxg подал соответствующий отчет об ошибке https://bugs.openjdk.java.net/browse/JDK-8036823 по строкамего ответ здесь.

Ответы [ 4 ]

3 голосов
/ 03 марта 2012

Я не думаю, что ваш дамп потока говорит, что ваши два потока "ждут двух разных других мониторов". Я думаю, что это говорит о том, что они оба ждут на одном мониторе, но в двух разных точках кода. Это может быть расположение в стеке, расположение экземпляра объекта или что-то еще. Это отличный документ о анализе дампов стека .

Может ли несколько потоков удерживать блокировку на одном мониторе в Java?

Нет. Ваш дамп стека показывает два потока, заблокированных на одном мониторе в одном и том же месте кода, но в разных фреймах стека - или независимо от того, какое это значение является зависимым от ОС.

Edit:

Я не уверен, почему дамп потока говорит о том, что в обоих потоках заблокирована строка, поскольку это разрешено только в том случае, если они находятся в методе 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 описывает это значение следующим образом:

Диапазон адресов, который дает оценку действительной области стека для потока

2 голосов
/ 06 марта 2014

Вы, вероятно, сталкиваетесь с косметической ошибкой в ​​процедурах трассировки стека в JVM при анализе сильно конфликтующих блокировок - она ​​может совпадать или не совпадать с этой ошибкой .

Дело в том, что ни одному из ваших потоков не удалось получить блокировку на SharedItemStateManager, как вы можете видеть из того факта, что они сообщают waiting for monitor entry.Ошибка заключается в том, что дальше в трассировке стека в обоих случаях они должны сообщать waiting to lock вместо locked.

Обходной путь при анализе странных трассировок стека, подобных этой, состоит в том, чтобы всегда проверять, что поток утверждает, чтоlocked объект также не ожидает получения блокировки для того же объекта.

(К сожалению, этот анализ требует перекрестной ссылки на номера строк в трассировке стека с исходным кодом, так как нет никакой связи междуцифры в заголовке waiting for monitor entry и в строке locked в трассировке стека. Согласно этому документу Oracle , число 0x00007f2a21278000 в строке TP-Processor184" daemon prio=10 tid=0x00007f2a7c056800 nid=0x47e7 waiting for monitor entry [0x00007f2a21278000] относится к оценкедействительная область стека для потока . Таким образом, он выглядит как идентификатор монитора, но это не так - и вы можете видеть, что два потока, которые вы дали, находятся по разным адресам в стеке.

2 голосов
/ 02 марта 2012

Когда поток блокирует объект, но wait () другой поток может заблокировать тот же объект. Вы должны увидеть несколько потоков, «удерживающих» одну и ту же блокировку в ожидании.

AFAIK, единственный другой случай - это когда несколько потоков заблокированы и ожидают и готовы повторно захватить блокировку, например. на уведомление все (). Они больше не ждут, но не могут продолжать, пока они снова не получат блокировку. (только один поток за раз может сделать это)

0 голосов
/ 13 мая 2013
"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)

В нашем дампе потоков у нас есть несколько потоков, блокирующих один и тот же монитор, но только один поток runnable . Вероятно, из-за конкуренции за блокировку , у нас есть 284 других потока, ожидающих блокировки. Несколько потоков имеют одинаковую блокировку? сказал, что это существует только в дампе потока, поскольку дамп потока не является атомарной операцией.

...