それはそこにある深刻な混乱したコードです。OP、あなたはこれを書いていませんが、つまずいただけで熱くなります。
まず、NewThread はスレッドではなく、Runnable です。同じことではなく、それには理由があります。しかし、そのコンストラクターは新しいスレッドを宣言し、すぐにそれを開始し、Runnable をある種のゾンビ スレッドに変えます。これは、そもそも Runnable を持つという目的全体を無効にし、ひどい考えです。スレッドの場合、ランナブルではなくスレッドを宣言します。Runnable を ThreadPool で使用したい場合はどうすればよいでしょうか? これらの Runnables を複数定義して、順番に開始したい場合はどうすればよいでしょうか? ある日 Runnable が Callable になったとしたら、その未来はどこに見えますか?
次に、侮辱に加えて、コードにはメインスレッドに並行コードがあります。これは教育目的ではなく、実際の価値はほとんどありません。実際には、通常、そのようなスレッド化されたコードを混在させることはなく、1 つの制御スレッド (メイン) と 1..n のワーカー スレッド (メインによって制御されます)。
スレッドとランナブルのポイントは、タスクの機能記述 (ランナブル) をライフサイクル動作 (スレッド) から分離することです。並列実行とスケーラビリティは、副次的なメリットです。それでは、それを反映するようにチュートリアル コードをリファクタリングしましょう。
class Countdown implements Runnable {
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
public class ThreadDemo2 {
public static void main(String args[]) {
Thread t = new Thread(new Countdown());
t.start();
try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
その方がいいです。現在、Runnable はスレッドのふりをすることはなく、いつ、どのように、または誰によって実行されるかについても気にしません。タスクが実行するはずの run() を実装するだけで、メイン スレッドはこの Runnable をコンストラクター引数として新しい Thread に渡し、それを start() します。これは、新しい Thread が呼び出すことを意味します。 Runnable の run()。しかし、もっとうまくやることができます: 2 つのスレッドは本質的に同じことをするので、そのように実装する必要があります:
class Countdown implements Runnable {
final String name;
final int length;
final int skip;
public Countdown(String name, int length, int skip) {
this.name = name;
this.length = length;
this.skip = skip;
}
public void run() {
try {
for(int i = length; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(skip);
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println("Exiting " + name);
}
}
public class ThreadDemo3 {
public static void main(String args[]) {
Thread t1 = new Thread(new Countdown("Child One", 5, 50));
Thread t2 = new Thread(new Countdown("Child Two", 5, 100));
t1.start();
t2.start();
}
}
これで、機能がライフサイクル管理から分離されました。カウントダウンは、名前が言うことを正確に実行する独自のクラスであり、メインにはこれ以上ワーカーロジックはありません。メインはカウントダウンを呼び出して開始するだけです。
OP、私の最大のアドバイスは、より良いチュートリアルを見つけることです。上記の grkvlt によって言及された Brian Goetz のチュートリアルは、はるかに優れています。Goetz (「Java Concurrency in Practice」) と Doug Lea (「Concurrent Programming in Java」) による本にもいくらかのお金を投資することをお勧めします。