Rahul khandelwal
Rahul khandelwal

Reputation: 331

Getting deadlock in java code

I have following three classes.

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

}

When I am executing main method from Helper.java, I am getting following output-

calling static method of derived class..

In load method of base class

After this execution is halt but the process is still running. So it seems that there is some deadlock, but I don't understand why is that. Help needed.

Upvotes: 2

Views: 149

Answers (1)

piet.t
piet.t

Reputation: 11921

When BaseClass is referenced for the fist time the class loader kicks in and wants to set up the class for use. So it loads the class and starts the static initializer block

static {
    load();
}

This calls the load-method and there you try to create an object of type DerivedClass. This will first try to call the super()-constructor, i.e. a method of class BaseClass - but BaseClass isn't fully initialized yet because its static initializer has not completed => deadlock.

Edit: Based on your comment I did some more research. Actually, things are not quite as simple as I assumed. The JVM is capable of dealing with recursive initialization so there is no problem in the single-threaded case. A description of the class-initialization-process can be found in section 5.5 of the JVM-specification.

What is the culprit here is actually a race-condition between the two initialization-processes.

Thread 1 reaches DerivedClass.isSynthetic("test"), and starts the initialization of DerivedClass.

Meanwhile thread 2 reaches BaseClass.init()and starts the initialization of BaseClass.

While initializing DerivedClass thread 1 recognizes it has to initialize the superclass. Since initialization of BaseClass is already in progress by thread 2 thread 1 has to wait for it to complete.

While initializing BaseClass thread 2 reaches DerivedClass dc = new DerivedClass();. Since initialization of DerivedClass is already in progress by thread 1 thread 2 has to wait for it to complete.

So actually this is a classical deadlock where two threads try to enter two critical codepaths ("initialization of class X") in different order (BaseClass->DerivedClass vs. DerivedClass->BaseClass) and ending up waiting for each other.

Adding some Thread.sleep(100); in the proper places will also show you that this is really a race-condition. During my tests sometimes the program completed successfully despite the cyclic dependency during initialization.

Upvotes: 2

Related Questions