как несколько потоков могут заблокировать один и тот же объект (как показано в дампе потока)

У меня есть следующий дамп потока, который показывает, что два потока блокируются на одном и том же объекте. И я не понимаю, что это на самом деле означает

    "pool-1-thread-2" prio=10 tid=0x00007fd6dc106000 nid=0x5d15 in Object.wait() [0x00007fd6d2067000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000007c3547770> (a java.lang.Object)
    at java.lang.Object.wait(Object.java:503)
    at test.TestDead$Foo.second(TestDead.java:22)
    at test.TestDead$Foo.first(TestDead.java:14)
    - locked <0x00000007c3547770> (a java.lang.Object)
    at test.TestDead$2.run(TestDead.java:45)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)

   Locked ownable synchronizers:
    - <0x00000007c35519e8> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"pool-1-thread-1" prio=10 tid=0x00007fd6dc104800 nid=0x5d14 in Object.wait() [0x00007fd6d2168000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000007c3547770> (a java.lang.Object)
    at java.lang.Object.wait(Object.java:503)
    at test.TestDead$Foo.second(TestDead.java:22)
    at test.TestDead$Foo.first(TestDead.java:14)
    - locked <0x00000007c3547770> (a java.lang.Object)
    at test.TestDead$1.run(TestDead.java:37)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)

   Locked ownable synchronizers:
    - <0x00000007c3551730> (a java.util.concurrent.ThreadPoolExecutor$Worker)

Что здесь на самом деле означает "заблокировано"?


person One Two Three    schedule 07.05.2015    source источник
comment
Спасибо за ссылку. Это именно та страница, которую я прочитал, прежде чем обратиться к StackOverflow.   -  person One Two Three    schedule 08.05.2015
comment
Можете ли вы показать всю трассировку стека? Два потока могут удерживать одну и ту же блокировку, если один из них ожидает.   -  person Piotr Praszmo    schedule 08.05.2015
comment
Сообщение @Banthar обновлено. Не могли бы вы объяснить этот бит о двух потоках, удерживающих одну и ту же блокировку? Я просто не понимаю. Я думал, что блокировка должна удерживаться одним и только одним потоком. Спасибо   -  person One Two Three    schedule 08.05.2015
comment
Поскольку wait() - это собственный метод, я предполагаю, что тот факт, что wait() разблокирует монитор, не отображается в дампе потока. Таким образом, оба потока блокируют монитор и вызывают wait (который разблокирует его изнутри), но он по-прежнему отображается как заблокированный в дампе потока.   -  person Andy    schedule 08.05.2015


Ответы (1)


В этом контексте заблокировано означает, что ваш работающий код Java вошел в блок synchronous, но еще не вышел из этого блока.

Как показывает дамп потока, вы вызываете wait(), который внутренне разблокирует монитор, связанный с блоком synchronous. Однако, поскольку вы блокируете ожидание и не вышли из синхронного блока, дамп потока по-прежнему показывает locked. Таким образом, можно иметь несколько потоков, отображающих locked в дампе потока, несмотря на то, что базовый монитор разблокирован.

Это легко продемонстрировать с помощью простого теста:

public class TestMonitor {

    synchronized public void lockAndWait() {
        try {
            wait();
        } catch ( InterruptedException ex ) {
            // Stifle
        }
    }

    public static void main( String args[] ) {
        TestMonitor tm = new TestMonitor();
        tm.lockAndWait();
    }
}

который при запуске выводит следующий дамп потока:

"main" prio=10 tid=0x00007f86c4008000 nid=0x5d35 in Object.wait() [0x00007f86cbae2000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000759055df8> (a TestMonitor) at java.lang.Object.wait(Object.java:503) at TestMonitor.lockAndWait(TestMonitor.java:5) - locked <0x0000000759055df8> (a TestMonitor) at TestMonitor.main(TestMonitor.java:13

Обратите внимание, что монитор все еще locked, несмотря на wait.

ОБНОВИТЬ

Если случай с одним потоком неубедителен, вы можете запустить приведенный выше пример с небольшими изменениями, и в этом случае вы увидите несколько потоков locked на одном мониторе в дампе потока:

public static void main( String args[] ) {
    final TestMonitor tm = new TestMonitor();

    Thread thread1 = new Thread( new Runnable() { public void run() { tm.lockAndWait(); } } );
    Thread thread2 = new Thread( new Runnable() { public void run() { tm.lockAndWait(); } } );
    thread1.start();
    thread2.start();
}
person Andy    schedule 07.05.2015