【问题标题】:Getting deadlock in java code在java代码中出现死锁
【发布时间】:2016-06-22 05:49:00
【问题描述】:

我有以下三个课程。

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 方法时,我得到以下输出 -

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

在基类的加载方法中

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

【问题讨论】:

标签: java multithreading concurrency deadlock


【解决方案1】:

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

static {
    load();
}

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

编辑: 根据您的评论,我做了更多的研究。其实,事情并没有我想象的那么简单。 JVM能够处理递归初始化,因此在单线程情况下没有问题。类初始化过程的描述可以在 JVM 规范的第 5.5 节中找到。

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

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

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

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

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

所以实际上这是一个典型的死锁,其中两个线程尝试以不同的顺序(BaseClass->DerivedClass 与 DerivedClass->BaseClass)进入两个关键代码路径(“类 X 的初始化”)并最终相互等待。

在适当的地方添加一些Thread.sleep(100); 也会告诉你这确实是一个竞争条件。在我的测试中,尽管初始化期间存在循环依赖,但有时程序会成功完成。

【讨论】:

  • 你解释的似乎是可能的,但是为什么System.out.println(DerivedClass.isSynthetic("test"));这里派生类的静态方法也处于死锁状态。当我删除对派生类的静态方法的调用时,执行工作正常,我得到的输出为:调用在基类派生类构造函数中完成对象创建。基础初始化
  • @Rahulkhandelwal 你说得对,JVM 比我想象的要复杂。我为真正的原因添加了一些解释。
  • 感谢您的解释。这真的很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多