繁体   English   中英

同步部分不阻止!

[英]synchronized section does not block!

我昨天注意到一些非常奇怪的事情。 似乎两个线程正在进入同时锁定在同一对象上的两个同步块。

包含相关代码的类( MyClass )看起来类似于:

private static int[]    myLock  = new int[0];

protected static int methodA(final long handle, final byte[] sort) {
    synchronized (myLock) {
        return xsMethodA(handle, sort);
    }
}

protected static int methodB(final long handle) {
    synchronized (myLock) {
        return xsMethodB(handle);
    }
}

我创建了一个运行上面类的应用程序的线程转储,当我看到这个时非常惊讶:

"http-8080-136" daemon prio=10 tid=0x00000000447df000 nid=0x70ed waiting for monitor entry [0x00007fd862aea000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.MyClass.methodA(MyClass.java:750)
    - locked <0x00007fd8a6b8c790> (a [I)
    at com.SomeOtherClass.otherMethod(SomeOtherClass.java:226)
    ...

"http-8080-111" daemon prio=10 tid=0x00007fd87d1a0000 nid=0x70c8 waiting for monitor entry [0x00007fd86e15f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.MyClass.methodB(MyClass.java:991)
    - locked <0x00007fd8a6b8c790> (a [I)
    at com.SomeOtherClass.yetAnotherMethod(SomeOtherClass.java:3231)
    ...

(为了简单起见,我改变了类和方法名称,所以不要被愚蠢的名字弄糊涂。)

似乎线程http-8080-136和http-8080-111都获得了对myLock的锁定。 它与对象地址相同的对象是: 0x00007fd8a6b8c790 Java运行时规范说明了synchronized关键字:

synchronized语句代表执行线程获取互斥锁(第17.1节),执行块,然后释放锁。 当执行线程拥有锁时, 没有其他线程可以获取锁 [ Java语言规范,14.19 ]

那怎么可能呢?

线程转储中有另外44个线程“等待”锁定。 这是线程正在等待的样子:

"http-8080-146" daemon prio=10 tid=0x00007fd786dab000 nid=0x184b waiting for monitor entry [0x00007fd8393b6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.MyClass.methodC(MyClass.java:750)
    - waiting to lock <0x00007fd8a6b8c790> (a [I)
    at com.SomeOtherClass.yetAnoterMethod2(SomeOtherClass.java:226)

我在hotspot-dev邮件列表上提出了同样的问题,并从Christopher Phillips那里得到了一个非常好的答案:


嗨Eduard

我认为它的线程转储具有误导性。

如果你真的认为2同时处于锁定状态,你应该得到一个gcore(外部一致)。

您看到“等待监视器条目”的状态实际上是MONITOR_WAIT,它可以在实际获取热锁之前表示以下代码:(也可以参见osThread.hpp中的OSThreadContendState)从:src / share / vm / runtime / synchronizer.cpp调用

3413      OSThreadContendState osts(Self->osthread());
3414      ThreadBlockInVM tbivm(jt);
3415
3416      Self->set_current_pending_monitor(this);
3417
3418      // TODO-FIXME: change the following for(;;) loop to straight-line code.
3419      for (;;) {
3420        jt->set_suspend_equivalent();
3421        // cleared by handle_special_suspend_equivalent_condition()
3422        // or java_suspend_self()
3423
3424        EnterI (THREAD) ;
3425
3426        if (!ExitSuspendEquivalent(jt)) break ;
3427
3428        //
3429        // We have acquired the contended monitor, but while we were
3430        // waiting another thread suspended us. We don't want to enter
3431        // the monitor while suspended because that would surprise the
3432        // thread that suspended us.

克里斯

线程转储是如何进行的? 如果线程没有暂停,则锁定所有权可能在转储一个线程和下一个线程之间发生了变化。

我认为相关的信息是:“等待监视器输入”,两个线程都是一样的。 由于两个线程(在线程转储中)都被标记为deamon线程,我想还必须有一个主线程同时运行。 主线程是否可能阻止其他两个线程的当前监视器所有者?

他们没有获得锁定,否则你会在堆栈跟踪中看到xsMethodA或xsMethodB。

暂无
暂无

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

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