Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using anonymous runnable class code goes in deadlock state but with lambda it works fine

I am trying to find out the cause behind below mentioned code. Here if I create Thread using anonymous inner class it goes into deadlock state but with lambda expressions it works fine. I tried to find the reason behind this behavior but I could not.

public class ThreadCreationTest {

    static {
        new ThreadCreationTest();
    }

    private void call() {
        System.out.println("Hello guys!!!");
    }

    public ThreadCreationTest() {

        // when we use this thread it goes in deadlock kind of state
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                call();
            }
        });

        // This one works fine.
        Thread thread = new Thread(() -> call());

        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public static void main(String... args) {
        System.out.println("Code finished...");
    }
}

with lambda expression output :

Hello guys!!!
Code finished...

with anonymous class :

code goes into deadlock state
like image 276
cody123 Avatar asked Oct 25 '16 13:10

cody123


1 Answers

Decompiling with javap the inner class shows the following for the run method:

public void run();
  descriptor: ()V
  flags: ACC_PUBLIC
  Code:
    stack=1, locals=1, args_size=1
       0: aload_0
       1: getfield      #12                 // Field this$0:Ltest/ThreadCreationTest;
       4: invokestatic  #22                 // Method test/ThreadCreationTest.access$0:(Ltest/ThreadCreationTest;)V
       7: return
    LineNumberTable:
      line 31: 0
      line 32: 7
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       8     0  this   Ltest/ThreadCreationTest$1;

Notice that there is a static synthetic method access$0 which in turn calls the private method call. The synthetic method is created because call is private and as far as the JVM is concerned, the inner class is just a different class (compiled as ThreadCreationTest$1), which cannot access call.

static void access$0(test.ThreadCreationTest);
  descriptor: (Ltest/ThreadCreationTest;)V
  flags: ACC_STATIC, ACC_SYNTHETIC
  Code:
    stack=1, locals=1, args_size=1
       0: aload_0
       1: invokespecial #68                 // Method call:()V
       4: return
    LineNumberTable:
      line 51: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature

Since the synthetic method is static, it is waiting for the static initializer to finish. However, the static initializer is waiting for the thread to finish, hence causing a deadlock.

On the other hand, the lambda version does not rely on an inner class. The bytecode of the constructor relies on an invokedynamic instruction (instruction #9) using MethodHandles:

public test.ThreadCreationTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=3, args_size=1
         0: aload_0
         1: invokespecial #13                 // Method java/lang/Object."<init>":()V
         4: new           #14                 // class java/lang/Thread
         7: dup
         8: aload_0
         9: invokedynamic #19,  0             // InvokeDynamic #0:run:(Ltest/ThreadCreationTest;)Ljava/lang/Runnable;
        14: invokespecial #20                 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
        17: astore_1
        18: aload_1
        19: invokevirtual #23                 // Method java/lang/Thread.start:()V
        22: aload_1
        23: invokevirtual #26                 // Method java/lang/Thread.join:()V
        26: goto          36
        29: astore_2
        30: invokestatic  #29                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
        33: invokevirtual #33                 // Method java/lang/Thread.interrupt:()V
        36: return
like image 63
M A Avatar answered Oct 18 '22 09:10

M A