使用匿名可运行的类代码进入死锁状态,但使用lambda它可以正常工作

cod*_*123 6 java lambda multithreading anonymous-class java-8

我试图找出下面提到的代码背后的原因.这里如果我使用匿名内部类创建Thread,它会进入死锁状态但是使用lambda表达式它可以正常工作.我试图找到这种行为背后的原因,但我不能.

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...");
    }
}
Run Code Online (Sandbox Code Playgroud)

使用lambda表达式输出:

Hello guys!!!
Code finished...
Run Code Online (Sandbox Code Playgroud)

匿名类:

code goes into deadlock state
Run Code Online (Sandbox Code Playgroud)

man*_*uti 5

使用javap内部类进行反编译会显示以下run方法:

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;
Run Code Online (Sandbox Code Playgroud)

请注意,有一个静态合成方法access$0,它反过来调用私有方法call.创建合成方法是因为它call是私有的,就JVM而言,内部类只是一个不同的类(编译为ThreadCreationTest$1),无法访问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
Run Code Online (Sandbox Code Playgroud)

由于合成方法是静态的,因此它正在等待静态初始化程序完成.但是,静态初始化程序正在等待线程完成,从而导致死锁.

另一方面,lambda版本不依赖于内部类.构造函数的字节码依赖于invokedynamic指令(指令#9),使用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
Run Code Online (Sandbox Code Playgroud)