【问题标题】:multithreading and static blocks多线程和静态块
【发布时间】:2012-06-21 07:09:15
【问题描述】:

我在我们的一个项目中遇到了一个奇怪的问题。我们使用 JUnit 来运行我们的单元测试,前段时间,我们开始并行运行 pur 测试以加快执行速度。大多数时候,一切都很好,但有时,我们几乎所有的测试都会失败。在下一次运行时,它们都再次通过而没有更改任何代码。

这些错误似乎表明某些静态实例未正确初始化或在多线程情况下完成初始化之前未使用。 (我无法调试这个,因为调试时问题从未出现过 -> Heisenbug。)

抱歉,我无法提供显示该错误的最小工作示例,因为它在尝试重现时会消失。

具体的问题是:当像下面这样声明一个变量时,当另一个线程调用 foo() 或 bar() 时,是否有可能没有完成 a 或 b 的初始化?我认为可以保证在调用任何方法之前执行静态块。或者可能存在类加载器问题?还是 JRE 中的已知错误(我们目前停留在 1.6.0_21,我们的 IT 部门尚未提供更新的版本)?

class C {
    private static final A a;
    private static final B b;

    static {
        a = new A(...);
        b = new B(...);
    }

    public static void foo() {
        useA();
    }

    public static void bar() {
        useB();
    }

}

我确信它与硬件无关,因为它出现在来自不同制造商的不同机器上。测试正在使用服务器 vm。

谢谢,

阿克塞尔

【问题讨论】:

  • new A()new B() 是否启动新线程?您是否尝试过隔离问题并创建一个重现该问题的SSCCE
  • 据我所知,将整个类与静态字段和方法一起使用是一种不好的做法,尤其是多线程。为什么不创建非静态类并将其存储在静态字段中?
  • 这就是这里所做的。 a 和 b 是提供预先计算值的类的实例。这两个类都是不可变的,并且具有返回这些预先计算的值的方法。计算在各自的类构造函数中完成。访问时只需要检查参数、计算索引并返回包含先前计算值的数组元素。

标签: java initialization static-block


【解决方案1】:

这很可能是由于并发问题,特别是当您调用static 的东西时。尝试同步您的线程,如下所示:

class C {
    private static final A a;
    private static final B b;

    static {
        a = new A(...);
        b = new B(...);
    }

    public synchronized static void foo() {
        useA();
    }

    public synchronized static void bar() {
        useB();
    }

}

【讨论】:

  • A 类和 B 类是不可变的并且经过全面测试的线程安全。这里应该不需要使用同步。 foo() 和 bar() 在我们的测试中被调用了数百万次,要么总是失败,要么永远不会失败,所以我认为这一定与初始化有关。
  • 静态字段被初始化一次(它们是类相关的而不是实例相关的)。您没有具体说明如何从 C 调用 A 和 B 实例,所以对我来说,它们在您的示例中是多余的。
  • 是的,初始化一次。在它们的初始化过程中似乎出了点问题。
  • 您是否尝试过我的解决方案?如果您如此确定,那么您所显示的代码绝对不是问题。问题可能出在 A 和 B 类的构造函数中。
  • 尝试解决方案的问题是错误只会偶尔出现一次 - 可能每周出现一次或两次。但我想现在我有一个线索。我认为我们在构造函数中使用了一个“损坏的”单例,即以非线程安全方式实现的单例(有趣的文章在这里:cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)。
【解决方案2】:

如果AB 创建线程或以其他方式在不同线程上执行代码,则可能会出现问题。无论如何,你真的希望静态是不可变的。

如果存在循环依赖关系,理论上有可能看到部分初始化的类,但不太可能。

【讨论】:

    猜你喜欢
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-27
    • 1970-01-01
    相关资源
    最近更新 更多