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
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
source share