Java class loading of anonymous classes and master classes interdependent issues

Qestion

/**
 * ClassInitializedOrder for : Java Classload Order Test
 *
 * @author <a href="mailto:[email protected]">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: Compile Error
  • D: these answers are wrong

Explain

Program execution, App Classloader will first load ClassInitializedOrder.class, are executed in the order of classes.

private static boolean initialized = false;

CASE 1

We all know that staticthe block will be initialized when the class is loaded, the next step will be to perform Thread thread = new Thread(() -&gt; initialized = true);our first look at the byte code of the current line:

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

Analysis #12can be seen that the processing needs of the current row ()is changed to handle anonymous class itself, InvokeDynamicbut also depends on the current which the main class of the current instruction execution, does not end the execution of the main class, the main class so it needs to wait for the end of execution, So will this stop, as follows:

Java class loading of anonymous classes and master classes interdependent issues

CASE 2

Continue to view bytecode:

 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

View #16, we can see here becomes new #16 // class com/sxzhongf/daily/question/july/ClassInitializedOrder$1, can clearly see from the previous invokeDynamicbecome a new anonymous class, then it's the result?

Java class loading of anonymous classes and master classes interdependent issues

Still the block. We try to change a line of code?

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();
        }
    }

We see that we just modify a line of code System.out.println("Runnable 代码块执行。");, then the result?

Java class loading of anonymous classes and master classes interdependent issues

The implementation of a successful return. why? Continue to view bytecode

 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

Check #16to see or newan anonymous class, and one is the same, why we can succeed? The current that is not dependent on the anonymous code information class of the main class. There is no up and down dependent, then we will not wait another situation occurs, of course, will not block.

Then there friends will ask, why wait for each other it? And here we joinhave the association, we look at its implementation code.

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

We can see that, first of all it is synchronizedkeyword modified, it shows that it also can only be one thread to access, and then look down, we can find concrete realization join, in fact, wait()be achieved, when the program sub-thread when the main thread to wait for the implementation class initialization is complete, but also rely on some elements of the object in the main thread. Then they will start to wait for the main thread initialization is complete, at this time, according to the order of execution classloader to load classes in #16will begin to wait, then the main class can not be initialized, causing each other now waiting phase.

Result

  • Anonymous initialization can not rely on built-in classes outside the class initialization
  • lambda expression invokeDynamicas part of the main class bytecode, the main class wait to begin initialization completion

In short, the class initialization phase, the object built-in class (Anonymous / Lambda) and the main class initialization interdependence can not appear

Guess you like

Origin blog.51cto.com/1917331/2422036