Using the anonymous code of the launch class is in a deadlock state, but it works fine with lambda

I am trying to find out the reason for the code below. Here, if I create Thread using an anonymous inner class, it goes into a deadlock state, but it works fine with lambda expressions. I tried to find the reason for this behavior, but 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 the output of a lambda expression:

 Hello guys!!! Code finished... 

with anonymous class:

 code goes into deadlock state 
+6
source share
1 answer

Decompiling with the javap 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; 

Note that there is a static synthetic access$0 method, which in turn calls the private call method. The synthetic method is created because the call is private, and as for the JVM, the inner class is just another class (compiled as ThreadCreationTest$1 ) that cannot access the 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 waits for the completion of the static initializer. However, the static initializer waits for the thread to complete and therefore causes a deadlock.

On the other hand, the lambda version does not rely on the inner class. The constructor byte code is based on the 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 
+5
source

Source: https://habr.com/ru/post/1011684/


All Articles