首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >同步部分不阻塞!

同步部分不阻塞!
EN

Stack Overflow用户
提问于 2010-07-13 09:03:34
回答 4查看 807关注 0票数 7

昨天我注意到一件很奇怪的事。两个线程似乎同时进入两个同步块,锁定在同一个对象上。

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

代码语言:javascript
复制
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);
    }
}

我创建了一个运行上述类的应用程序的线程转储,并且非常惊讶地看到了以下内容:

代码语言:javascript
复制
"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关键字做了如下说明:

同步语句代表正在执行的线程获取互斥锁(§17.1),执行块,然后释放锁。当正在执行的线程拥有锁时,没有其他线程可以获得锁。[Java语言规范,14.19]

,那么这怎么可能呢?

线程转储中还有44个线程“等待”锁。如果线程正在等待,则如下所示:

代码语言:javascript
复制
"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)
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-07-14 12:23:57

我在hotspot邮件列表中也问过同样的问题,并从Christopher那里得到了一个很好的回答:

嗨,爱德华

我认为这是一个错误的线索转储。

如果您真的认为这2同时在锁中,您可能会得到一个gcore (这是外部一致的)。

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

代码语言:javascript
复制
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.

克里斯

票数 4
EN

Stack Overflow用户

发布于 2010-07-13 09:07:34

线程转储是怎么处理的?如果线程没有暂停,锁所有权可能在转储一个线程和下一个线程之间发生变化。

票数 1
EN

Stack Overflow用户

发布于 2010-07-13 09:13:43

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3235599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档