<clinit>死锁的问题

youlong699 2013-05-01
静态变量初始化的死锁的一个疑问。
这个是毕大神的一个case http://hellojava.info/?p=88, 然后研究了下,还不太明白。主要是jstack dump里线程的状态不理解。
我找了个初始化死锁的线程:

"call-cStr" prio=6 tid=0x0257cc00 nid=0x18a4 in Object.wait() [0x04c3f000]
   java.lang.Thread.State: RUNNABLE
    at C.<clinit>(StaticInit.java:40)
    at StaticInit$2.run(StaticInit.java:13)
    at java.lang.Thread.run(Thread.java:662)

"call-bStr" prio=6 tid=0x0257a400 nid=0x1ddc in Object.wait() [0x04baf000]
   java.lang.Thread.State: RUNNABLE
    at B.<clinit>(StaticInit.java:28)
    at StaticInit$1.run(StaticInit.java:7)
    at java.lang.Thread.run(Thread.java:662)


代码是这样的:
public class StaticInit {
    public static void main(String[] arg){
        Thread th1 = new Thread(new Runnable(){
            public void run(){
                System.out.println(B.bStr);
            }
        },"call-bStr") ;
       
        Thread th2 = new Thread(new Runnable(){
            public void run(){
                System.out.println(C.cStr);
            }
        },"call-cStr");
        th1.start();
        th2.start();
    }
}

class B {
    static{
        try{
            System.out.println("Binit start");
            Thread.sleep(1000);
        }catch(InterruptedException ex){
        }
        System.out.println("b->cStr " + C.cStr);
    }
    static String bStr = "bStr" ;
}

class C {
    static{
        try{
            System.out.println("Cinit start");
            Thread.sleep(1000);
        }catch(InterruptedException ex){
        }
        System.out.println("c->b.bStr " + B.bStr);
    }
        static String cStr ="cStr";
}


疑问点在于
"call-cStr" prio=6 tid=0x0257cc00 nid=0x18a4 in Object.wait() [0x04c3f000]
   java.lang.Thread.State: RUNNABLE
State 是 RUNNABLE, 然后第一行又是输出的Object.wait(), 这个岂不是不一致了?
另外, 对于这种jvm加锁的,有没有好办法看到它的锁?  如果调用了本地代码导致了死锁,是不是jstack都表现为这种情况?

:)
RednaxelaFX 2013-05-01
youlong699 写道
疑问点在于
"call-cStr" prio=6 tid=0x0257cc00 nid=0x18a4 in Object.wait() [0x04c3f000]
   java.lang.Thread.State: RUNNABLE
State 是 RUNNABLE, 然后第一行又是输出的Object.wait(), 这个岂不是不一致了?
另外, 对于这种jvm加锁的,有没有好办法看到它的锁?  如果调用了本地代码导致了死锁,是不是jstack都表现为这种情况?

是的,Thread.State为RUNNABLE但前面显示Object.wait()是不一致,这个显示内容其实有误。Object.wait()是正确的。

HotSpot VM在显示stack trace时,对VM内锁住对象的情况处理得不好,无法将其正确反映出来。这包括VM内直接用ObjectLocker来锁对象的,也包括通过JNI的MonitorEnter来锁对象的情况。以前写过个笔记演示这个状况:https://gist.github.com/rednaxelafx/2204011。还写过另一个笔记,说ThreadMXBean获取锁信息的方法可以正确处理native frame锁住对象的情况:https://gist.github.com/rednaxelafx/2223542

jstack输出的stack trace还有另外一种很奇葩的情况,就是可能会有多个线程看起来锁住了同一个对象。以前我也写过相关笔记:http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2012-July/004106.html
ticmy 2013-05-02
有必要提醒一点的是,bluedavy的那个问题不是因为<clinit>死锁导致的。
youlong699 2013-05-04
RednaxelaFX 写道


jstack输出的stack trace还有另外一种很奇葩的情况,就是可能会有多个线程看起来锁住了同一个对象。以前我也写过相关笔记:http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2012-July/004106.html


谢R大指点。 又长见识了:)
youlong699 2013-05-04
ticmy 写道
有必要提醒一点的是,bluedavy的那个问题不是因为<clinit>死锁导致的。

我本以为我看懂了。。 被你这么一说又不懂了。

可否进一步指点一下?
ticmy 2013-05-04
youlong699 写道
ticmy 写道
有必要提醒一点的是,bluedavy的那个问题不是因为<clinit>死锁导致的。

我本以为我看懂了。。 被你这么一说又不懂了。

可否进一步指点一下?


后来他不是又发了一篇文章解释了
youlong699 2013-05-05
ticmy 写道

我本以为我看懂了。。 被你这么一说又不懂了。

可否进一步指点一下?

后来他不是又发了一篇文章解释了


后来又发了两篇文章,一个cpu sy高排查的case http://hellojava.info/?p=99 和 cpu sy高case和static case(续) http://hellojava.info/?p=101
这两个都没有对死锁的这个case再做解释吧? 
第二篇对 static final 的编译做了说明。
m635674608 2013-06-01
能解释下这个情况吗????
youlong699 2013-07-11
m635674608 写道
能解释下这个情况吗????

恩, 最近忙没来逛。就是<clinit>死锁的问题,这里隐蔽的原因在于是锁在了静态字段,而非静态初始化块。但是静态字段的初始化会被收集到<clinit>里。
关于<clinit>加锁可以看下示例初始化相关的资料。 《深入理解jvm虚拟机》里也有比较全面的介绍
Global site tag (gtag.js) - Google Analytics