-4

チュートリアル Web サイトでこのコードを見つけました。

class NewThread implements Runnable {
   Thread t;
   NewThread() {
      // Create a new, second thread
      t = new Thread(this, "Demo Thread");
      System.out.println("Child thread: " + t);
      t.start(); // Start the thread
   }

   // This is the entry point for the second thread.
   public void run() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Child Thread: " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
     } catch (InterruptedException e) {
         System.out.println("Child interrupted.");
     }
     System.out.println("Exiting child thread.");
   }
}

public class ThreadDemo {
   public static void main(String args[]) {
      new NewThread(); // create a new thread
      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.");
   }
}

次の行では、引数の目的は何ですか。またthis、最初の引数の意味は何ですか。

 t = new Thread(this, "Demo Thread");

また、このコードの予想される動作 (フロー) は何ですか?

4

4 に答える 4

0

それはそこにある深刻な混乱したコードです。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」) による本にもいくらかのお金を投資することをお勧めします。

于 2013-08-20T16:13:45.667 に答える