匿名クラスとマスタークラスのJavaクラスのロード相互依存の問題

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

回答

  • initialized = true
  • B: initialized = false
  • C:コンパイルエラー
  • D:これらの答えが間違っています

説明します

プログラムの実行は、アプリケーションクラスローダーが最初にロードされますClassInitializedOrder.class、クラスの順序で実行されています。

private static boolean initialized = false;

CASE 1

我々は、すべてのことを知っているstaticクラスがロードされたときにブロックが初期化されます、次のステップは実行することになりThread thread = new Thread(() -&gt; 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だけでなく、現在の命令の実行のメインクラスは、メインクラスの実行を終了しない電流に依存し、メインクラスはので、それは実行の終了を待つ必要があり、次のようにこれは、停止します。

匿名クラスとマスタークラスのJavaクラスのロード相互依存の問題

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それは結果だ、新しい匿名クラスになりますか?

匿名クラスとマスタークラスのJavaクラスのロード相互依存の問題

まだブロック。我々は、コードの行を変更してみては?

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 代码块执行。");、その結果を?

匿名クラスとマスタークラスのJavaクラスのロード相互依存の問題

成功したリターンを実現。なぜ?バイトコードを表示し続けます

 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

チェック#16見たりするnew匿名クラス、もう1つは同じですが、なぜ我々は成功することができますか?メインクラスの匿名のコード情報クラスに依存しない現在。その後、我々はブロックされません、もちろん、別の状況が発生した待機しません、何の上下依存はありません。

そして、そこに友人はそれお互いを待つ理由、聞いてきます?そして、ここで我々はjoin、我々はその実装コードを見て、関連性を持っています。

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

我々はそれがすべての最初の、それを見ることができsynchronized、キーワード変更、それはまた、唯一の私たちが実際には、参加する具体的な実現を見つけることができ、アクセスに一つのスレッドも、その後見下ろすことができることを示しwait()たときにプログラムサブスレッド、達成されますメインスレッドが実装クラスの初期化を待つとき、完全ですが、また、メインスレッド内のオブジェクトのいくつかの要素に依存しています。その後、彼らはメインスレッドの初期化を待つために開始します。この時点で、クラスの中にロードするために、実行クラスローダの順序に従って、完了した#16後、メインクラスがお互い今待っ相を引き起こし、初期化することができない、待つことを開始します。

結果

  • 匿名の初期化は、クラスの初期化の外に組み込みクラスに依存することはできません
  • ラムダ表現invokeDynamicメインクラスのバイトコードの一部として、メインクラスは、初期化完了を開始するのを待ちます

短い、クラス初期化フェーズにおいて、オブジェクトビルトインクラス(匿名/ラムダ)とメインクラス初期化相互依存が表示できません

おすすめ

転載: blog.51cto.com/1917331/2422036