Qestion /** * ClassInitializedOrder for : Java Classload Order Test * * @author <a href="http://www.likecs.com/mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> * @since 2019/7/20 */ // CASE 1 public class ClassInitializedOrder { private static boolean initialized = false; static { println("static 代码块执行。"); Thread thread = new Thread(() -> initialized = true); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { println("main 函数执行。"); System.out.println("initialized = " + initialized); } private static void println(Object o){ System.out.println(o); } } ------------------------------------------------------------------- // CASE 2 public class ClassInitializedOrder { private static boolean initialized = false; static { println("static 代码块执行。"); Thread thread = new Thread(new Runnable() { @Override public void run() { println("Runnable 代码块执行。"); initialized = true; } }); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { println("main 函数执行。"); System.out.println("initialized = " + initialized); } private static void println(Object o){ System.out.println(o); } Answer
A: initialized = true
B: initialized = false
C: 编译错误
D: 以上答案都是错的
Explain程序执行的时候,App Classloader 会首先加载ClassInitializedOrder.class, 按照类的顺序依次执行。
private static boolean initialized = false;
CASE 1我们都知道,static块会在类加载的时候初始化,那么下一步会执行到Thread thread = new Thread(() -> initialized = true);我们先来看一下当前行的字节码:
static {}; descriptor: ()V flags: ACC_STATIC Code: stack=3, locals=2, args_size=0 0: iconst_0 1: putstatic #7 // Field initialized:Z 4: new #11 // class java/lang/Thread 7: dup 8: invokedynamic #12, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 13: invokespecial #13 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V 16: astore_0 17: aload_0 18: invokevirtual #14 // Method java/lang/Thread.start:()V 21: aload_0 22: invokevirtual #15 // Method java/lang/Thread.join:()V 25: goto 33 28: astore_1 29: aload_1 30: invokevirtual #17 // Method java/lang/InterruptedException.printStackTrace:()V 33: return分析#12可以看到当前行的处理需要()也就是改匿名类本身来处理,InvokeDynamic指令的在当前的执行又依赖于当前所处的主类,主类并没有执行结束,因此它需要等待主类执行结束,因此会在此停顿,如下:
CASE 2继续查看字节码:
static {}; descriptor: ()V flags: ACC_STATIC Code: stack=4, locals=2, args_size=0 0: iconst_0 1: putstatic #1 // Field initialized:Z 4: ldc #14 // String static 代码块执行。 6: invokestatic #2 // Method println:(Ljava/lang/Object;)V 9: new #15 // class java/lang/Thread 12: dup 13: new #16 // class com/sxzhongf/daily/question/july/ClassInitializedOrder$1 16: dup 17: invokespecial #17 // Method com/sxzhongf/daily/question/july/ClassInitializedOrder$1."<init>":()V 20: invokespecial #18 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V 23: astore_0 24: aload_0 25: invokevirtual #19 // Method java/lang/Thread.start:()V 28: aload_0 29: invokevirtual #20 // Method java/lang/Thread.join:()V 32: goto 40 35: astore_1 36: aload_1 37: invokevirtual #22 // Method java/lang/InterruptedException.printStackTrace:()V 40: return查看#16,我们可以看到这里变成了new #16 // class com/sxzhongf/daily/question/july/ClassInitializedOrder$1,可以明显看到从之前的invokeDynamic 变成了 new 一个匿名类,那么它的结果呢?
依然还是block.我们来换一行代码试试?
public class ClassInitializedOrder { private static boolean initialized = false; static { println("static 代码块执行。"); Thread thread = new Thread(new Runnable() { @Override public void run() { //println("Runnable 代码块执行。"); System.out.println("Runnable 代码块执行。"); //initialized = true; } }); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } }我们看到我们只是修改了一行代码System.out.println("Runnable 代码块执行。");,那么结果呢?
执行成功的返回了。为什么?继续查看字节码
static {}; descriptor: ()V flags: ACC_STATIC Code: stack=4, locals=2, args_size=0 0: iconst_0 1: putstatic #9 // Field initialized:Z 4: ldc #14 // String static 代码块执行。 6: invokestatic #3 // Method println:(Ljava/lang/Object;)V 9: new #15 // class java/lang/Thread 12: dup 13: new #16 // class com/sxzhongf/daily/question/july/ClassInitializedOrder$1 16: dup 17: invokespecial #17 // Method com/sxzhongf/daily/question/july/ClassInitializedOrder$1."<init>":()V 20: invokespecial #18 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V 23: astore_0 24: aload_0 25: invokevirtual #19 // Method java/lang/Thread.start:()V 28: aload_0 29: invokevirtual #20 // Method java/lang/Thread.join:()V 32: goto 40 35: astore_1 36: aload_1 37: invokevirtual #22 // Method java/lang/InterruptedException.printStackTrace:()V 40: return