在java代码中获得死锁

时间:2016-06-22 05:49:00

标签: java multithreading concurrency deadlock

我有三节课。

BaseClass.java

public class BaseClass {

    static {
        load();
    }

    public static void init() {
        System.out.println("base init");
    }

    private static void load() {
        System.out.println("In load method of base class");
        DerivedClass dc = new DerivedClass();
        System.out.println("Object creation done.");
    }

}

DerivedClass.java

public class DerivedClass extends BaseClass {

    public DerivedClass() {
        System.out.println("derived class constructor");
    }

    public static boolean isSynthetic(String _attr) {
        return true;
    }
}

Helper.java

public class Helper {

    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                BaseClass.init();
            };
        };
        t.start();
        System.out.println("calling static method of derived class..");
        System.out.println(DerivedClass.isSynthetic("test"));
    }

}

当我从Helper.java执行main方法时,我得到以下输出 -

  

调用派生类的静态方法..

     

在基类的加载方法

此操作暂停后但进程仍在运行。 所以似乎有一些僵局,但我不明白为什么会这样。 需要帮助。

1 个答案:

答案 0 :(得分:2)

当第一次引用BaseClass时,类加载器会启动并希望设置该类以供使用。所以它加载类并启动静态初始化程序块

static {
    load();
}

这会调用load - 方法,并尝试创建DerivedClass类型的对象。这将首先尝试调用super() - 构造函数,即类BaseClass的方法 - 但BaseClass尚未完全初始化,因为其静态初始化程序尚未完成=>死锁。

修改 根据你的评论我做了一些更多的研究。实际上,事情并不像我想象的那么简单。 JVM能够处理递归初始化,因此单线程情况下没有问题。类初始化过程的描述可以在JVM规范的5.5节中找到。

这里的罪魁祸首是两个初始化过程之间的竞争条件。

线程1到达DerivedClass.isSynthetic("test"),并开始DerivedClass的初始化。

同时,线程2到达BaseClass.init()并开始BaseClass的初始化。

初始化DerivedClass线程1时识别它必须初始化超类。由于线程2线程1已经在进行BaseClass的初始化,因此线程1必须等待它完成。

初始化BaseClass主题2达到DerivedClass dc = new DerivedClass();。由于线程1线程2已经在进行DerivedClass的初始化,因此线程2必须等待它完成。

所以实际上这是一个经典的死锁,其中两个线程试图以不同的顺序(BaseClass-> DerivedClass vs. DerivedClass-> BaseClass)输入两个关键的代码路径(“类X的初始化”)并最终等待每个其他

在适当的位置添加一些Thread.sleep(100);也会向您显示这确实是一种竞争条件。在我的测试期间,有时程序成功完成,尽管初始化期间存在循环依赖。