57

join()Javaのスレッドで使用されるメソッドに混乱しています。次のコードでは:

// Using join() to wait for threads to finish.
class NewThread implements Runnable {

    String name; // name of thread
    Thread t;

    NewThread(String threadname) {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
        t.start(); // Start the thread
    }
// This is the entry point for thread.

    public void run() {
        try {
            for (int i = 5; i > 0; i--) {
                System.out.println(name + ": " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println(name + " interrupted.");
        }
        System.out.println(name + " exiting.");
    }
}

class DemoJoin {

    public static void main(String args[]) {
        NewThread ob1 = new NewThread("One");
        NewThread ob2 = new NewThread("Two");
        NewThread ob3 = new NewThread("Three");
        System.out.println("Thread One is alive: "
                + ob1.t.isAlive());
        System.out.println("Thread Two is alive: "
                + ob2.t.isAlive());
        System.out.println("Thread Three is alive: "
                + ob3.t.isAlive());
// wait for threads to finish
        try {
            System.out.println("Waiting for threads to finish.");
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (InterruptedException e) {
            System.out.println("Main thread Interrupted");
        }
        System.out.println("Thread One is alive: "
                + ob1.t.isAlive());
        System.out.println("Thread Two is alive: "
                + ob2.t.isAlive());
        System.out.println("Thread Three is alive: "
                + ob3.t.isAlive());
        System.out.println("Main thread exiting.");
    }
}

このプログラムの出力例を次に示します。

New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
Thread One is alive: true
Thread Two is alive: true
Thread Three is alive: true
Waiting for threads to finish.
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Two: 3
Three: 3
One: 2
Two: 2
Three: 2
One: 1
Two: 1
Three: 1
Two exiting.
Three exiting.
One exiting.
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread Exiting

上記のコードでは:

  1. 私はプログラムの実行の流れを理解することができません.そして、作成されたときにob1コンストラクターが呼び出され t.start()ます. では、なぜこれが起こっているのですか?run()main()

  2. join()メソッドは、それが呼び出されたスレッドが終了しないまで待機するために使用されますが、ここで出力にスレッドの代替出力が表示されるのはなぜですか??

そして、の使用joinがこれである場合、の使用は何synchronizedですか??

ここで基本的な概念が欠けていることは知っていますが、理解できないので助けてください。

4

12 に答える 12

166

スレッドのスケジューリングはスレッド スケジューラによって制御されることを理解する必要があります。そのため、通常の状況ではスレッドの実行順序は保証されません。

join()ただし、スレッドが作業を完了するまで待機するために使用できます。

たとえば、あなたの場合

ob1.t.join();

このステートメントは、スレッドtの実行が終了するまで返されません。

これを試して、

class Demo {
   Thread t = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    Thread t1 = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    t.start(); // Line 15
    t.join();  // Line 16
    t1.start();
}

上記の例では、メイン スレッドが実行されています。15 行目に到達すると、スレッド t がスレッド スケジューラで使用可能になります。メイン スレッドが 16 行目に到達するとすぐに、スレッドtが終了するのを待ちます。

threadまたは thread に対してt.join何もしなかったことに注意してください。これは、それを呼び出したスレッド (つまり、スレッド) にのみ影響を与えました。tt1main()

編集:

t.join();例外であるtryため、ブロック内にある必要があります。そうしないと、コンパイル時にエラーが発生します。したがって、次のようになります。throwsInterruptedException

try{
    t.join();
}catch(InterruptedException e){
    // ...
}
于 2013-08-28T05:51:27.513 に答える
6

まず、作成時ob1にコンストラクターが呼び出され、実行が開始されます。その際t.start()も別スレッドで実行します。新しいスレッドが作成されると、メインスレッドと並行して実行されることに注意してください。そのため、メインは次のステートメントで再び実行を開始します。

AndJoin()ステートメントは、子スレッドが孤立するのを防ぐために使用されます。メインクラスで呼び出さなかった場合join()、メインスレッドは実行後に終了し、子スレッドは引き続きステートメントを実行します。Join()すべての子スレッドが実行を完了するまで待機し、メイン メソッドのみが終了します。

この記事を読んで、大いに役立ちます。

于 2013-08-28T05:13:12.833 に答える
4

私はプログラムの実行の流れを理解することができません.ob1が作成されると、t.start()が書かれている場所でコンストラクターが呼び出されますが、それでもrun()メソッドは実行されず、main()メソッドが実行を続けます. では、なぜこれが起こっているのですか?

メインは同じ優先順位を共有するため、これはスレッドスケジューラに依存します。start() を呼び出しても、run() がすぐに呼び出されるわけではありません。スレッドの実行を選択するときは、スレッド スケジューラに依存します。

join() メソッドは、それが呼び出されたスレッドが終了しないまで待機するために使用されますが、ここで出力にスレッドの代替出力が表示されるのはなぜですか??

これは、コード内の Thread.sleep(1000) が原因です。その行を削除すると、ob1 が ob2 の前に終了し、ob2 が ob3 の前に終了することがわかります (join() で予想されるように)。それはすべて、ob1、ob2、および ob3 がいつ開始されたかによって異なります。sleep を呼び出すと、(コード内で) >= 1 秒間スレッドの実行が一時停止され、スケジューラが待機中の他のスレッドを呼び出す機会が与えられます (同じ優先度)。

于 2014-02-25T06:23:45.687 に答える
1

JVM と基盤となる OS は、物事をスケジューリングする際にかなりの自由度があります。個々のスレッドからの出力が表示される前に「スレッドが終了するのを待っています」まで到達するという事実は、単にスレッドの起動に時間がかかることを意味している可能性があります (つまり、スレッドが「 alive" およびrun()メソッドが実際に実行を開始したとき)。スレッドの出力をもっと早く見ることができるかもしれませんが、どちらの方法でも保証されていません。

join()に関しては、参加しているスレッドが完了した後にのみ発生することを保証するだけです。そのため、3 つのjoin()呼び出しが連続している場合でも、スレッドが特定の順序で終了する必要があるわけではありません。これは単に、最初にob1を待つことを意味します。ob1が終了しても、ob2ob3はまだ実行中か、すでに終了している可能性があります。それらが終了すると、他のjoin()呼び出しはすぐに返されます。

同期は、複数のスレッドが同じオブジェクトにアクセスして変更を加える場合に特に使用されます。同期ブロックは、2 つのスレッドによって同時に実行されることは決してないことが保証されています。

于 2013-08-28T05:22:15.250 に答える
1

ob1 が作成されると、「t.start()」が記述されている場所でコンストラクターが呼び出されますが、run() メソッドは実行されず、main() メソッドがさらに実行されます。では、なぜこれが起こっているのですか?

ここでは、スレッドとメインスレッドの優先度が同じです。優先度の等しいスレッドの実行は、完全にに依存しますThread schedular。どちらが最初に実行されるかは期待できません。

join() メソッドは、それが呼び出されたスレッドが終了しないまで待機するために使用されますが、ここで出力にスレッドの代替出力が表示されるのはなぜですか??

ここで、メインスレッドからの以下のステートメントを呼び出します。

     ob1.t.join();
     ob2.t.join();
     ob3.t.join();

ob1.tそのため、メイン スレッドは, ob2.t,スレッドが終了するのを待ちますob3.t( Thread#join docを調べます)。したがって、3 つのスレッドすべてが正常に実行され、その後メイン スレッドが完了します。

于 2013-08-28T05:22:54.050 に答える
1

私のコメント:

出力を見ると、出力はスレッド名である One、Two、Three と混合され、同時に実行されます。スレッドがメインメソッドで実行されていないといつ言ったのかわかりません。

あなたの質問を理解したかどうかわかりません。しかし、私は自分の答えを理解できるものにしています。それがあなたの助けになることを願っています。

1) 次に、コンストラクターと呼ばれるオブジェクトを作成しました。コンストラクトには、スレッドを開始する start メソッドがあり、run() メソッド内に記述された内容が実行されます。

したがって、3 つのオブジェクト (3 つのスレッド - 1、2、3) を作成すると、3 つのスレッドすべてが同時に実行を開始しました。

2) 結合と同期 これらは 2 つの異なるものです。同期とは、共通のリソースを共有する複数のスレッドがあり、一度に 1 つのスレッドがそのリソースを使用する必要がある場合です。たとえば、DepositThread、WithdrawThread などのスレッドは、共通のオブジェクトを BankObject として共有します。したがって、DepositThread が実行されている間、WithdrawThread は同期されている場合は待機します。スレッド間通信には、wait()、notify()、notifyAll() が使用されます。詳細については、グーグルで検索してください。

Join()については、複数のスレッドが動いているときですが、参加します。たとえば、2 つのスレッド t1 と t2 があり、それらがマルチスレッド環境で実行されている場合、出力は次のようになります: t1-0 t2-0 t1-1 t2-1 t1-2 t2-2

t1.join() を使用すると、次のようになります: t1-0 t1-1 t1-2 t2-0 t2-1 t2-2

これは、特定の条件でスレッドを混同しない場合があり、(共有リソースではなく) 別のスレッドの完了に依存する場合にリアルタイムで使用されるため、join() メソッドを呼び出すことができます。

于 2013-08-28T05:35:25.967 に答える
1

糸通し第一のルール「糸通しは楽しい」…

私はプログラムの実行の流れを理解することができません.ob1が作成されると、コンストラクターが呼び出さt.start()れますが、run()メソッドは実行されず、main()メソッドは実行を続けます. では、なぜこれが起こっているのですか?

これはまさに起こるべきことです。を呼び出すThread#startと、スレッドが作成され、実行のスケジュールが設定されます。すぐに (またはそれに十分近い) 実行される場合とそうでない場合があります。それはスレッドスケジューラに帰着します。

これは、スレッドの実行がどのようにスケジュールされているか、およびシステムで他に何が起こっているかにかかっています。通常、各スレッドには、「スリープ」に戻されて別のスレッドの実行が許可される前に、実行するための短い時間が与えられます (明らかに、複数のプロセッサ環境では、同時に複数のスレッドを実行できますが、試してみましょうシンプルにしてください;))

スレッドもyield実行される可能性があり、システム内の他のスレッドが実行される可能性があります。

あなたは試すことができます

NewThread(String threadname) {
    name = threadname;
    t = new Thread(this, name);
    System.out.println("New thread: " + t);
    t.start(); // Start the thread
    // Yield here
    Thread.yield();
}

そして、スレッドの実行方法に違いが生じる可能性があります...同様に、短期間は可能ですがsleep、これにより、スレッドが一定期間の実行で見落とされる可能性があります(これが必要な場合もあれば、必要な場合もあります)しないでください)...

join()メソッドは、それが呼び出されたスレッドが終了しないまで待機するために使用されますが、ここで出力にスレッドの代替出力が表示されるのはなぜですか??

あなたが質問を述べた方法は間違っています...戻ってくる前に、それが死ぬjoinのを待ちます。Threadたとえば、 の結果に依存している場合、 を使用して、結果を取得する前に がいつ終了したかを知るThreadことができます。joinThread

同様に、スレッドをポーリングすることもできますが、これにより、Thread代わりにより適切に使用できる CPU サイクルが消費されます...

于 2013-08-28T05:14:43.020 に答える
0

join() は java.lang.Thread クラスのインスタンス メソッドであり、join() メソッドを使用して、main から開始されたすべてのスレッドが開始された順序で終了し、main が最後に終了するようにすることができます。つまり、このスレッドが終了するのを待ちます。

例外: join() メソッドは InterruptedException をスローします。

スレッドの状態: スレッド で join() メソッドが呼び出されると、実行中から待機中の状態になります。そして、スレッドが死ぬのを待ちます。

同期ブロック: スレッドは、join() メソッドを呼び出す前にオブジェクト ロックを取得する必要はありません。つまり、join() メソッドは同期ブロックの外部から呼び出すことができます。

待ち時間: join(): このスレッドが終了するのを待ちます。

public final void join() throws InterruptedException;

このメソッドは内部的に join(0) を呼び出します。また、タイムアウト 0 は永久に待機することを意味します。

join(long millis) – 同期されたメソッド このスレッドが終了するまで、最大で millis ミリ秒待機します。タイムアウト 0 は、永久に待機することを意味します。

public final synchronized void join(long millis)
    throws InterruptedException;

public final synchronized void join(long millis, int nanos)
    throws InterruptedException;

結合方法の例

class MyThread implements Runnable {
     public void run() {
           String threadName = Thread.currentThread().getName();
           Printer.print("run() method of "+threadName);
           for(int i=0;i<4;i++){
                Printer.print("i="+i+" ,Thread="+threadName);
           }         
     }
}

public class TestJoin {
     public static void main(String...args) throws InterruptedException {
           Printer.print("start main()...");

           MyThread runnable = new MyThread();
           Thread thread1=new Thread(runnable);
           Thread thread2=new Thread(runnable);

           thread1.start();
           thread1.join();

           thread2.start();
           thread2.join();

           Printer.print("end main()");
     }
}

class Printer {
     public static void print(String str) {
           System.out.println(str);
     }
}

Output:
     start main()...
     run() method of Thread-0
     i=0 ,Thread=Thread-0
     i=1 ,Thread=Thread-0
     i=2 ,Thread=Thread-0
     i=3 ,Thread=Thread-0
     run() method of Thread-1
     i=0 ,Thread=Thread-1
     i=1 ,Thread=Thread-1
     i=2 ,Thread=Thread-1
     i=3 ,Thread=Thread-1
     end main()

注: thread1.join() を呼び出すと、メイン スレッドは Thread-1 が終了するまで待機します。

join(long millis) を使うプログラムを見てみましょう

最初に、join(1000) が Thread-1 で呼び出されますが、1000 ミリ秒が経過すると、メイン スレッドが再開し、thread2 を開始できます (メイン スレッドは Thread-1 が終了するのを待ちません)。

class MyThread implements Runnable {
     public void run() {
           String threadName = Thread.currentThread().getName();
           Printer.print("run() method of "+threadName);
           for(int i=0;i<4;i++){
                try {
                     Thread.sleep(500);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
                Printer.print("i="+i+" ,Thread="+threadName);
           }         
     }
}

public class TestJoin {
     public static void main(String...args) throws InterruptedException {
           Printer.print("start main()...");

           MyThread runnable = new MyThread();
           Thread thread1=new Thread(runnable);
           Thread thread2=new Thread(runnable);

           thread1.start();

           // once 1000 millisec are up,
           // main thread can resume and start thread2.
           thread1.join(1000);

           thread2.start();
           thread2.join();

           Printer.print("end main()");
     }
}

class Printer {
     public static void print(String str) {
           System.out.println(str);
     }
}

Output:
     start main()...
     run() method of Thread-0
     i=0 ,Thread=Thread-0
     run() method of Thread-1
     i=1 ,Thread=Thread-0
     i=2 ,Thread=Thread-0
     i=0 ,Thread=Thread-1
     i=1 ,Thread=Thread-1
     i=3 ,Thread=Thread-0
     i=2 ,Thread=Thread-1
     i=3 ,Thread=Thread-1
     end main()

詳細については、私のブログを参照してください。

http://javaexplorer03.blogspot.in/2016/05/join-method-in-java.html

于 2016-05-12T04:06:05.957 に答える