Static field initialization in Java

Ennis Yan :

I encountered this problem when doing a question on LeetCode: https://leetcode.com/problems/print-in-order/

Consider two submissions:

1.

class Foo {
    private static int signal = 0;
    public Foo() {}

    public synchronized void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        signal += 1;
        notifyAll();
    }

    public synchronized void second(Runnable printSecond) throws InterruptedException {
        while(signal != 1)
            wait();

        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        signal += 1;
        notifyAll();
    }

    public synchronized void third(Runnable printThird) throws InterruptedException {
        while(signal != 2)
            wait();

        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
        notifyAll();
    }
}

2.

class Foo {
    private static int signal = 0;
    public Foo() {signal = 0;}

    public synchronized void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        signal += 1;
        notifyAll();
    }

    public synchronized void second(Runnable printSecond) throws InterruptedException {
        while(signal != 1)
            wait();

        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        signal += 1;
        notifyAll();
    }

    public synchronized void third(Runnable printThird) throws InterruptedException {
        while(signal != 2)
            wait();

        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
        notifyAll();
    }
}

Try submitting these two and you'll find submission 1 will result in Time Limit Exceeded while submission 2 will be accepted.

The only difference is that in submission 2, I explicitly added a statement signal = 0; to initialize the static variable. It should play no difference as I have already given this variable a default value in private static int signal = 0;, so what is going on here. Is there any subtleties in the static field initialization in Java that I did not know?

Thank you very much.

Willis Blackburn :

LeetCode runs several different test cases against your solution. Let's assume that LeetCode is running a single JVM and running all the test cases in that JVM, but it is instantiating a new Foo for each case.

When running the first case, signal is zero, and your code works as expected. But at the end of this test case signal is now 2, because the test case increments it twice. Since it is static, it is shared among all instances of Foo. Even though LeetCode instantiates a new Foo for the second test case, the static signal is still 2. The first method increments it to 3, but then the test hangs because the condition while (signal != 1) is always true.

Initializing signal to 0 in the Foo constructor has the effect of resetting signal before the second and subsequent test runs.

There's no reason to make signal static here. It should be a regular non-static member so that each instance of Foo gets a new signal initialized to zero.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=358435&siteId=1