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(() -> 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
それは結果だ、新しい匿名クラスになりますか?
まだブロック。我々は、コードの行を変更してみては?
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
チェック#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
メインクラスのバイトコードの一部として、メインクラスは、初期化完了を開始するのを待ちます
短い、クラス初期化フェーズにおいて、オブジェクトビルトインクラス(匿名/ラムダ)とメインクラス初期化相互依存が表示できません