Mutually recursively defined static fields causes program to freeze but not without threads and not with gcj?

StackOverflow https://stackoverflow.com/questions/17980598

Question

Here is some simple code:

class B {final static int x = C.x;}
class C {final static int x = B.x;}
class A {
    static {
        System.out.println("A static{}");
        new Thread() { public void run() { new B(); }}.start();
        new Thread() { public void run() { new C(); }}.start();
    }
    public static void main(String[] args) {
        System.out.println("A main");
        System.out.println("B.x: " + B.x);
        System.out.println("C.x: " + C.x);
    }
}

B.x and C.x are defined in terms of each other. I thought this should not compile but it does.

It freezes in main when I try to run it:

$ javac *.java && java A
A static{}
A main

Why?

Yet, it works fine in gcj:

$ gcj --main=A -o a *.java && ./a
A static{}
A main
B.x: 0
C.x: 0

Why?

Also, if I get rid of the threads,

class B {final static int x = C.x;}
class C {final static int x = B.x;}
class A {
    static {
        System.out.println("A static{}");
        new B(); 
        new C(); 
    }
    public static void main(String[] args) {
        System.out.println("A main");
        System.out.println("B.x: " + B.x);
        System.out.println("C.x: " + C.x);
    }
}

It works fine in both java and gcj:

$ javac *.java && java A
A static{}
A main
B.x: 0
C.x: 0
$ gcj --main=A -o a *.java && ./a
A static{}
A main
B.x: 0
C.x: 0

And all the variables are set to 0. Why? Shouldn't this fail to compile since the variables are static final and are never assigned anywhere?

Was it helpful?

Solution

You are creating a deadlock condition which may or may not be a problem depending on how fast you start your threads.

When you use a class for the first time, it initialises the class and calls the static blocks. It does this in a thread safe manner and no other thread can access the class until that is done.

You have two threads and in the deadlock case, one has class B and wants class C, the other has class C and want class B.

As this is pretty quick, one thread can run to completion before the other start and in this case, no deadlock occurs.

Shouldn't this fail to compile since the variables are static final and are never assigned anywhere?

You have assigned the value, however you access the value while it is being initialised which is why you see the default value of 0.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top