私はそのanswer-からコードを取るhttps://stackoverflow.com/a/9286697/2674303
私はそのコードのリード線がデッドロックする理由を私は理解していないことを、現在のトピックを作成した理由:
public class Lock implements Runnable {
static {
System.out.println(Thread.currentThread().getId() + "# Getting ready to greet the world");
try {
System.out.println(Thread.currentThread().getId() + "# before lock creation");
Lock target = new Lock();
System.out.println(Thread.currentThread().getId() + "# after lock creation");
Thread t = new Thread(target);
t.start();
System.out.println(Thread.currentThread().getId() + "# awaiting thread finish");
t.join();
System.out.println(Thread.currentThread().getId() + "# static block finished");
} catch (InterruptedException ex) {
System.out.println("won't see me");
}
}
public static void main(String[] args) {
System.out.println(Thread.currentThread() + "Hello World! ");
}
public void run() {
System.out.println(Thread.currentThread().getId() + "# Started thread");
Thread t = new Thread(new Lock());
t.start();
}
}
私はそれに多くの時間を開始しようとしましたが、それは常にデッドロックにつながります。
出力は常に同じ:
1# Getting ready to greet the world
1# before lock creation
1# after lock creation
1# awaiting thread finish
13# Started thread
私は非静的初期化子、それのコードはデッドロックにつながることはないとなった後に作ってみました。だから私は、それが何らかの形で静的クラスの初期化に関連していると信じています。
あなたはそれを説明してもらえますか?
回答
おかげでジョンスキートの答えのために、私はその一例を理解するために私を防止コード行を削除し、物事を単純化するために:
public class Lock implements Runnable {
static {
try {
Thread thread = new Thread(new Lock());
thread.start();
thread.join();
} catch (InterruptedException ex) {
System.out.println("won't see me");
}
}
public static void main(String[] args) {
System.out.println(Thread.currentThread() + "Hello World! ");
}
public void run() {
new Lock();
}
}
それはあまりにもデッドロックにつながります
新しいスレッドを呼び出すようにしようとしているrun
中にLock
クラス。この方法自体は、新しいインスタンスを作成しようとしますLock
。それはそれを行うことができない1までLock
クラスが初期化されて終わりました。JVMはその初期化が完了するまで別のスレッドがすでにので、ブロックを、クラスを初期化していることを知っています。
残念ながら、その初期化が完了するまではできませんrun
ので、の完了、t.join()
呼び出し。デッドロック-それは何かを行うことができます前に、進捗状況を作るために他を必要とする二つのスレッドのそれぞれはそう。
それは間違いなく、まさにこの理由のため、クラス初期化子に多くの作業を行うことを避けるために試してみる価値です。
つまり、すべての場合にも起こるrun()
方法自体は空でした。しかし、それはそれよりも悪いです-ので、run()
この方法は、それが別のスレッドを作成されるまで終了して待っていないであろうという完全な呼び出しにスレッドrun()
などだから、失敗の他の原因だということ-それは、基本的にはJVMまでのspawnのスレッドがリソースを使い果たします。そうでもタイプ初期化子を削除すると、作業コードにあなたを取得することはできません。
タイプの初期化が必要とされる理由の観点では、参照JLSのセクション12.4.1を:
クラスまたはインタフェースタイプTは、次のいずれかの最初の発生直前に初期化されます。
- Tはクラスであり、Tのインスタンスが作成されます。
- Tによって宣言された静的メソッドが呼び出されます。
- Tによって宣言された静的フィールドが割り当てられます。
- Tによって宣言された静的フィールドが使用され、フィールドは、一定の変数(§4.12.4)ではありません。
表現new Lock()
は常にどちらかの初期化Lock
(もちろん、すでに起こったかもしれない、)完全に初期化のための、または待機。
1あなたは、コードを分割する場合はrun
、あなたがのインスタンスを作成するようにLock
して、ログインし、その後、スレッドを起動し、あなたはそれはの創造だ表示されますLock
ブロックしています。