【问题标题】:Can several threads hold a lock on the same monitor in Java?Java 中的多个线程可以在同一个监视器上持有锁吗?
【发布时间】:2012-01-19 12:44:06
【问题描述】:

目前我们正在分析一个 tomcat 线程转储。以同一方式运行的所有线程的单个线程转储 Tomcat 上的 time 包含以下几行:

...
"soldOutJmsConsumerContainer-1" prio=10 tid=0x00007f8409c14800 nid=0x231 in Object.wait() [0x00007f8403a9f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:485)
    at com.tc.object.RemoteObjectManagerImpl.waitUntilRunning(RemoteObjectManagerImpl.java:150)
    at com.tc.object.RemoteObjectManagerImpl.basicRetrieve(RemoteObjectManagerImpl.java:216)
    - locked <0x00007f847612c820> (a com.tc.object.RemoteObjectManagerImpl)
...
"catalina-exec-33" daemon prio=10 tid=0x0000000041bc4000 nid=0x832 in Object.wait() [0x00007f8400f73000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:485)
    at com.tc.object.RemoteObjectManagerImpl.waitUntilRunning(RemoteObjectManagerImpl.java:150)
    at com.tc.object.RemoteObjectManagerImpl.basicRetrieve(RemoteObjectManagerImpl.java:216)
    - locked <0x00007f847612c820> (a com.tc.object.RemoteObjectManagerImpl)
...
"catalina-exec-109" daemon prio=10 tid=0x0000000041469800 nid=0x1e87 in Object.wait() [0x00007f83f84c1000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:485)
    at com.tc.object.RemoteObjectManagerImpl.waitUntilRunning(RemoteObjectManagerImpl.java:150)
    at com.tc.object.RemoteObjectManagerImpl.basicRetrieve(RemoteObjectManagerImpl.java:216)
    - locked <0x00007f847612c820> (a com.tc.object.RemoteObjectManagerImpl)

特别是我们不明白

- locked <0x00007f847612c820> (a com.tc.object.RemoteObjectManagerImpl)

根据我们的理解,它表示当时三个线程正在对同一个监视器持有一个锁。在我们的理解中 根据JLS,这是不可能的。

我们对线程转储的解释是否正确?

【问题讨论】:

    标签: java concurrency locking monitor terracotta


    【解决方案1】:

    看起来所有这些线程都在等待与监视器关联的条件,即它们调用了该监视器的wait() 方法。

    当线程在它拥有的监视器上调用wait()时,它会暂时释放监视器,当从wait()返回时需要重新获取它。因此,您可以拥有多个线程,这些线程曾经拥有一个监视器,但现在正在 wait() 方法中等待。

    【讨论】:

    • +1 但是...您能具体解释一下为什么这与所有其他答案不同吗?如果他们正在等待一个条件,释放了监视器,现在正试图重新获得它,这到底是怎么回事,与所有其他答案不完全相同?
    • @NoozNooz42:嗯,有可能这些线程已经收到通知,现在正在等待重新获取监视器,但这不太可能。我想强调一点,这些线程更有可能尚未收到通知,而是在等待通知。
    • @axtavt 线程不可能等待重新获取。如果他们正在等待重新获得他们的状态将是BLOCKED 而不是WAITING
    【解决方案2】:

    什么意思是“-locked (a com.tc.object.RemoteObjectManagerImpl)”。

    这意味着它在该锁的同步块内。它可以是 WAITING (在这种情况下另一个线程可以获取/持有锁,或者 RUNNING 在这种情况下它持有锁。

    【讨论】:

    • 同意。我把它解释为它在监视器上等待
    【解决方案3】:

    那些线程正在等待获取锁,而不是持有锁。

    【讨论】:

    • -1。等待条件(在wait() 方法中)与等待获取锁不同。
    • 我不确定这种解释是否正确。 RemoteObjectManagerImpl#basicRetrieve() 已同步。堆栈跟踪必须自下而上读取。堆栈跟踪说:1)在同步方法中,ID为0x00007f847612c820的监视器持有一个锁。然后它跳到waitUntilRunning,然后它在那里等待Object#wait()。是的,它们正在等待对象,但它们都通过同步方法传递。由于涉及到 Terracotta,我们假设它是 Terracotta 中的一个错误。所以我们的问题是:什么意思是“-locked (a com.tc.object.RemoteObjectManagerImpl)”。
    • @axtavt 线程在无法获得锁时被阻塞。只有在 wait() 方法中,线程才在等待。 docs.oracle.com/javase/7/docs/api/java/lang/Thread.State.html
    • 这里没有错误。基本上,L1 正在等待集群启动并运行。在 L1 成功完成连接到 L2 之前,不会提供任何请求......希望这会有所帮助。如果由于某种原因,这似乎没有发生,您可能想在 Terracotta 论坛上提出问题(提供有关版本的更多详细信息以及您在做什么)...
    【解决方案4】:

    没有不同的线程不能对相同的对象持有锁。其他人持有该锁,转储中的所有线程都在等待该锁。

    【讨论】:

      猜你喜欢
      • 2012-03-21
      • 2016-05-28
      • 2015-02-02
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 2013-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多