0

以下は私のサンプルコードです。a.start()呼び出したときにスレッドを作成し、すぐに「実行」を出力する必要があります。しかし、なぜ「開始」を20回印刷した後に呼び出されるのですか。

run()スレッド「a」は、すぐに呼び出す必要がないことをどのように判断しますか。

public class JoinTest implements Runnable {

    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(new JoinTest());
        a.start();

        for (int i = 0; i < 20; i++) {
            System.out.print("Begin");
        }
        Thread.sleep(1000);

        a.join();
        System.out.print("\nEnd");
    }

    public void run() {
        System.out.print("\nRun");
    }
}

出力:

BeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBegin
Run
End

スレッドの動作について少し混乱しています。

私の意見では、メソッドが呼び出される前"run"に印刷される"begin"ため、前に印刷する必要join()があり、結合時にスレッド「a」と呼ばれるメソッドは実行を終了している必要があり、その時点で結合を呼び出すことは役に立たないはずです。

4

4 に答える 4

2

スレッドを開始し、すぐに印刷を行ってからスリープします。あなたのコードを見ると、スレッドがバックグラウンドで開始され、メインスレッドが作業を進めているため、実際に前に見ることが期待されます。さらに、メソッドは同期されるため、ループ内でそのロックを繰り返し取得するため、2 番目のスレッドが介入する可能性はさらに低くなります。BeginRunprint

呼び出しの有無にかかわらず、コードをThread.sleep排除して試しました。joinどちらの場合も動作は同じです。ほとんどの場合、最後に来て、単語Runの間にインターリーブされることがあります。Begin同期されたブロックを使用した同時実行の単純なモデルによって期待されるとおりにすべてが正確に行われます。

Runメソッドを呼び出すかどうかに関係なく、他のすべての前に確実に出力されるコードのわずかなバリエーションを次に示しますjoin。変更されたのは、sleepコールの位置だけです。

public class JoinTest implements Runnable
{
  public static void main(String[] args) throws InterruptedException {
    Thread a = new Thread(new JoinTest());
    a.start();

    Thread.sleep(1000);
    for (int i = 0; i < 20; i++) {
      System.out.print("Begin");
    }

    a.join();
    System.out.print("\nEnd");
  }

  public void run() {
    System.out.print("\nRun");
  }
}
于 2015-07-30T09:29:38.980 に答える
2

スレッドを呼び出しても、そのメソッドの実行がすぐstart()にトリガーされるとは限りません。run()スレッドは開始済みとしてマークされていますが、メインスレッドはその実行をforループに追い込んでいます。sleep()次に、メインスレッドがステートメントに到達すると、JVM がスレッドに切り替わります。

于 2015-07-30T09:32:07.490 に答える
0

start()メソッドはスレッドのメソッドを呼び出しますが、run()これには少し時間がかかりますが、「開始」ループの一部またはすべてが完了するのに十分な場合があります。これを自分のマシンで実行すると、最初と 2 番目の「開始」の間に「実行」出力が表示されます。マシンが各コマンドを実行するのにかかる時間を確認できるように、タイムスタンプを付けて出力してみてください。

public class JoinTest implements Runnable {

    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(new JoinTest());
        a.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("Begin " + System.nanoTime());
        }
        Thread.sleep(1000);

        a.join();
        System.out.println("End " + System.nanoTime());
    }

    public void run() {
        System.out.println("Run " + System.nanoTime());
    }
}

その時点で呼び出すと、join()がスレッドの完了を待機するため、a.join() 'End' の前に常に 'Run' の出力が表示されます。

于 2015-07-30T11:38:23.377 に答える
0

join() を使用して多くのシナリオを試しましたが、「実行」は常に「開始」の後に出力されますが、結合ステートメントを削除すると「実行」は常に「開始」の前に出力されます。なんで?

許可されているからです。それが理由です。.start() を呼び出すとすぐに、2 つのスレッドが作成されます。プログラムが .join() のような同期メソッドを呼び出すまでは、どのスレッドをいつ実行するかを決定するのは、JVM 実装とオペレーティング システム次第です。

メイン スレッドからの呼び出しは、スレッドがそのメソッドを完了するa.join()まで、メイン スレッドを強制的に待機させます。arun()

呼び出しがないa.join()場合、Java 言語仕様では、スレッドがメイン スレッドに戻る前に作業を完了することを許可し、スレッドが実行を開始する前にメイン スレッドが関数の最後に到達することを許可します。起こる。aa.start()main()a

それは完全にJVMとOS次第です。

物事が起こる順序を制御したい場合は、synchronizedブロック、同期オブジェクト、およびメソッド (.join() など) を使用する必要があります。

しかし、注意してください!特定の順序で物事を強制すればするほど、プログラムがスレッドを使用するメリットは少なくなります。ほとんどの場合、スレッドが互いに独立して機能できるようにプログラムを設計することをお勧めします。

于 2015-07-30T13:41:00.080 に答える