このスレッド結合コードはどういう意味ですか?


156

このコードでは、2つのjoinとbreakはどういう意味ですか?t1.join()原因となるt2まで停止するようにt1終了?

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread t2 = new Thread(new EventThread("e2"));
t2.start();
while (true) {
   try {
      t1.join();
      t2.join();
      break;
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
}


3
スレッドの終了をブロックして待機するため、なぜwhileループを使用したのですか?
Mehdi

@MahdiElMasaoudiスレッドが中断されても待機し続けると思いますか?おそらくそれを行うための素晴らしい方法ではない
フォレストホプキンサ2017年

役に立った場合は、ここで回答を受け入れることを忘れないでください。
グレー

既に述べwhile(true)たように、joinメソッドを呼び出すためには必要ありません。
Chaklader Asfak Arefe

回答:


311

このスレッド結合コードはどういう意味ですか?

Thread.join()メソッドjavadocsから引用するには:

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

おそらくメインスレッドであるサンプルコードを実行しているスレッドがあります

  1. メインスレッドが作成され、開始さt1t2スレッドを。2つのスレッドが並行して実行を開始します。
  2. メインスレッドはt1.join()t1スレッドが終了するのを待つために呼び出します。
  3. t1スレッドは完了し、t1.join()メインスレッドのメソッドが返します。呼び出しが行われるt1前に既に終了している可能性があることに注意してください。そのjoin()場合、join()呼び出しはすぐに戻ります。
  4. メインスレッドはt2.join()t2スレッドが終了するのを待つために呼び出します。
  5. t2スレッドの完了(または前に完了している場合がありますt1スレッドがした)とt2.join()メインスレッドのメソッドが返します。

t1t2スレッドは並行して実行されていますが、スレッドを開始したメインスレッドは、スレッドが続行する前に終了するのを待つ必要があることを理解することが重要です。これは一般的なパターンです。また、t1および/またはt2終了している可能性が前にメインスレッドの呼び出しjoin()それらの上に。その場合、join()待機せず、すぐに戻ります。

t1.join() t1が終了するまでt2を停止させるという意味ですか?

いいえ。呼び出しているメインスレッドはt1.join()実行を停止し、t1スレッドが完了するまで待機します。t2スレッドが並列に実行されているとの影響を受けていないt1か、t1.join()すべてのコール。

try / catchに関して、join()throws InterruptedExceptionは、呼び出しているメインスレッドjoin()自体が別のスレッドによって中断される可能性があることを意味します。

while (true) {

whileループに結合があるのは奇妙なパターンです。通常、最初の結合を実行してから、2番目の結合でInterruptedException適切な処理を行います。それらをループに入れる必要はありません。


24
+1これは非常に奇妙なパターンで、おそらく削除できます。
m0skit0 2013

3
t1が最初に終了すると、t2が終了します。それは逐次的なプロセスのようです。1つのスレッドが最初に終了し、次に他のスレッドが終了します。マルチスレッドの意味は何ですか?
user697911 2013

9
t1t2は並行して実行できるためです。それmainが続行する前に、両方が終了する必要があるというだけです。これは、@ user697911の典型的なパターンです。
グレー

3
while(私は推測)、それは再試行したいので、ループが存在しjoin()1が中断された場合の呼び出しを?私は確かに@ user697911のようにそれを書きません。
グレー

5
ループは、両方のことを確実にするためにそこにあるt1t2仕上がり。すなわち。をt1スローするとInterruptedException、ループバックしてを待ちt2ます。別の方法は、各Try-Catchで両方のスレッドを待機することです。これにより、ループを回避できます。また、によってはEventThread、1つのスレッドではなく2つのスレッドを実行しているため、この方法で実行することは理にかなっています。
Michael Bisbjerg 2013年

68

これはお気に入りのJavaインタビューの質問です。

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread e2 = new Thread(new EventThread("e2"));
t2.start();

while (true) {
    try {
        t1.join(); // 1
        t2.join(); // 2  These lines (1,2) are in in public static void main
        break;
    }
}

t1.join()つまり、t1は「最初に終了したい」のようなものを言います。同じことがの場合にも当てはまりt2ます。開始t1またはt2スレッド(この場合はmainメソッド)に関係なく、mainはタスクが終了するまで待機しt1t2終了します。

しかし、重要な点は、ダウン注意する、t1そしてt2自分自身は無関係に並行して実行呼び出しシーケンスに参加することができますt1してt2。それは待たなければならないmain/daemonスレッドです。


3
良い例え。「並列に実行できます」について:では何ですか?メインスレッドが最初にt1を待機し、その後、t2を待機することが重要です。(メインスレッドの観点から)t1またはt2が何をしているかは関係ありません
Alex

1
「メイン/デーモン」スレッドについて言及している。メインは理解していますが、デーモンはそれとは関係ありません。メインスレッドは非デーモンです。
グレー

1
t1.join(); t2.join();結合を実行するスレッドは、両方のスレッドが終了するまで続行できません。他に非常に珍しいコードがない場合、結合の順序は重要ではありません。
デビッドシュワルツ

t2.join()は、t1が終了したときにのみ呼び出されるのでしょうか?
Leo Droidcoder、2017年

つまり、t1スレッドとt2スレッドの実行を「シリアル化」する場合は、メインスレッドがt1(およびその後t2)を開始したため、t1.join()をt1.start()の直後に配置し、もちろんそれを削除する必要があります。トライ/キャッチ。明らかに、そうすると、結果として並列処理が失われます。
dobrivoje

47

join()スレッドが完了するのを待つことを意味します。これはブロッカーメソッドです。メインスレッド(を実行するスレッドjoin())は、その作業が終了するt1.join()までラインで待機し、t1に対して同じことを行いt2.join()ます。


29

写真は千の言葉の価値があります。

    Main thread-->----->--->-->--block##########continue--->---->
                 \                 |               |
sub thread start()\                | join()        |
                   \               |               |
                    ---sub thread----->--->--->--finish    

役立つことを願っています。詳細については、ここをクリックしてください


3
明確で正確。
dobrivoje

10

スレッドtAがtB.join()を呼び出すと、その原因はtBの終了またはtA自体の中断を待つだけでなく、tBの最後のステートメントとtAスレッドのtB.join()の後の次のステートメントとの間に発生前の関係を作成します。

スレッド内のすべてのアクションは、他のスレッドがそのスレッドのjoin()から正常に戻る前に発生します。

プログラムを意味します

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        threadB.join();

        while (true) 
            System.out.print(sharedVar);
    }
}

常に印刷する

>> 1111111111111111111111111 ...

しかしプログラム

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        // threadB.join();  COMMENT JOIN

        while (true)
            System.out.print(sharedVar);
    }
}

印刷できるだけでなく

>> 0000000000 ... 000000111111111111111111111111 ...

だが

>> 00000000000000000000000000000000000000000000 ... 

常に「0」のみ。

Javaメモリモデルでは、heppens-beforeの関係なしに、スレッドBからメインスレッドに「sharedVar」の新しい値を「転送」する必要がないため(スレッド開始、スレッド結合、「synchonized」キーワードの使用、AtomicXXX変数の使用など)。


5

簡単に言えば、完了
t1.join()後に戻りますt1
thread t1には何もしませんが、終了するまで待機します。
当然、次のコード はリターンt1.join()後にのみ実行され t1.join()ます。


1
t1.join()が+1を返した後にのみ実行されます
mohsen.nour 2018

3

結合の Oracleドキュメントページから

このjoinメソッドにより、1つのスレッドが別のスレッドの完了を待つことができます。

t1が、Thread現在スレッドが実行されているオブジェクトの場合、

t1.join() : causes the current thread to pause execution until t1's thread terminates.

t2が、Threadそのスレッドが現在実行中のオブジェクトである場合、

t2.join(); causes the current thread to pause execution until t2's thread terminates.

joinAPIは低レベルAPIであり、以前のバージョンのJavaで導入されました。並行性の面で、多くのことが一定期間(特にjdk 1.5リリースで)変更されました。

java.util.concurrent APIでも同じことができます。いくつかの例は

  1. invokeAllを使用するExecutorService
  2. CountDownLatchの使用
  3. 使用ForkJoinPool又はnewWorkStealingPoolのをExecutors(Javaの8以降)

関連するSEの質問を参照してください。

すべてのスレッドがJavaでの作業を完了するまで待ちます


1

私にとって、Join()の動作は常に混乱を招きました。そのように覚えようとしないでください。

その下には、純粋なwait()およびnotify()メカニズムがあります。

すべてのオブジェクト(t1)でwait()を呼び出すと、呼び出しオブジェクト(メイン)が待合室(ブロック状態)に送信されることは誰でも知っています。

ここでは、メインスレッドが内部でwait()であるjoin()を呼び出しています。したがって、メインスレッドは通知を受けるまで待機します。実行が完了すると(スレッド完了)、t1によって通知が行われます。

通知を受け取った後、mainは待合室を出て実行を続行します。


0

それが役に立てば幸い!

package join;

public class ThreadJoinApp {

    Thread th = new Thread("Thread 1") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());
            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    Thread th2 = new Thread("Thread 2") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());

            //Thread 2 waits until the thread 1 successfully completes.
            try {
            th.join();
            } catch( InterruptedException ex) {
                System.out.println("Exception has been caught");
            }

            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    public static void main(String[] args) {
        ThreadJoinApp threadJoinApp = new ThreadJoinApp();
        threadJoinApp.th.start();
        threadJoinApp.th2.start();
    }

    //Happy coding -- Parthasarathy S
}

-3

メインスレッドがスレッドt1とt2を開始するとします。ここで、t1.join()が呼び出されると、メインスレッドはスレッドt1が終了するまで一時停止してから再開します。同様に、t2.join()が実行されると、メインスレッドは、スレッドt2が終了して再開されるまで、再び一時停止します。

だから、これはそれがどのように機能するかです。

また、whileループはここでは実際には必要ありませんでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.