4

I am facing a weird problem in one of our projects. We use JUnit to run our unit tests, and some time ago, we started to run pur tests in parallel to speed up execution. Most of the time, all is fine, but from time to time, nearly all of our tests fail. On the next run, they all pass again without any code being changed.

The errors seem to indicate that some static instances are not initialised correctly or used before initialisation is completed in the multithreaded case. (I cannot debug this, since the problem never once showed up when debugging -> Heisenbug.)

Sorry I cannot provide a minimal working example showing the bug because it disappears when trying to reproduce.

The concrete question is: when declaring a variable like below, is there any chance initialisation of a or b hasn't completed when foo() or bar() are called by another thread? I thought the static block would be guaranteed to execute before any of the methods can be called. Or can there be class loader issues? Or known errors in the JRE (we are currently stuck at 1.6.0_21, newer versions are not yet provided by our IT department)?

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();
    }

}

I am sure it's not hardware related since it shows up on different machines from different manufacturers. Tests are using the server vm.

Thank you,

Axel

Axel
  • 13,939
  • 5
  • 50
  • 79
  • Does `new A()` or `new B()` start new threads? Have you tried to isolate the problem and create a [SSCCE](http://sscce.org) that reproduces the issue? – assylias Jun 19 '12 at 09:05
  • As I know that's a bad practice to use whole class with static fields and methods, especially with multithreading. Why don't you create non-static class and store it in static field? – alaster Jun 19 '12 at 11:02
  • That is what is done here. a and b are instances of classes that provide precalculated values. Both classes are immutable and have methods that return these precalculated values. The calculations are done in the respective classes constructors. On access there is not more than checking arguments, calculating an index and returning the array element containing the previously calculated value. – Axel Jun 19 '12 at 11:15

2 Answers2

0

This is most likely due to concurrency problems, specially if you're calling static stuff. try synchronizing your threads, like this:

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();
    }

}
m0skit0
  • 25,268
  • 11
  • 79
  • 127
  • classes A and B are immutable and thoroughly tested thread safe. There should be no need to use synchronized here. foo() and bar() are called millions of times during our tests, and either always fail or never fail, so I think it must have to do with initialisation. – Axel Jun 19 '12 at 09:09
  • Static fields are initialized **once** (they're class-related and not instance-related). You didn't specify anything about how A and B instances are called in from C, so to me they're superfluous in your example. – m0skit0 Jun 19 '12 at 09:14
  • Yes, initialized once. And it seems something goes wrong during their initialisation. – Axel Jun 19 '12 at 11:09
  • Did you try my solution anyway? And if you're so sure then it's definitely not a problem in the code you're showing. The problem is probably in the constructors for A and B classes. – m0skit0 Jun 19 '12 at 14:15
  • The problem with trying a solution is the error only shows up once in a while - perhaps once or twice a week. But I think now I have a clue. I think somewhere down the path we have a "broken" singleton that is used in the constructors, i.e. a singleton implemented in a non-thread safe manner (interesting article here: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html). – Axel Jun 20 '12 at 06:28
0

There can be issues if A or B create a thread or otherwise execute code on a different thread. You really want statics to be immutable anyway.

It is in theory possible, if there are circular dependencies, to see a partially initialised class, but it's quite unlikely.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305