7

またはそれは?
私は次のスレッドオブジェクトを持っています:

Thread myThread = new Thread(pObject);

ここで、pObjectはRunnableインターフェイスを実装するクラスのオブジェクトであり、次のようにスレッドオブジェクトでstartメソッドが呼び出されます。

myThread.start();

さて、私の理解では、start()が呼び出されると、JVMは暗黙的に(そしてすぐに)run()メソッドを呼び出します。このメソッドは(私の場合のように)オーバーライドされる可能性があります。

ただし、私の場合、start()メソッドは(必要に応じて)すぐには呼び出されないようですが、呼び出し元のブロックから他のステートメント/メソッドが完了するまで、つまり、start()呼び出しの後に次のようなメソッドがある場合は次のようになります。

myThread.start();
doSomethingElse();

doSomthingElse()は、run()メソッドが実行される前に実行されます。
おそらく、start()が呼び出された直後にrun()が常に呼び出されるという最初の前提が間違っています。助けてください!ここでも、start()の直後にrun()を実行する必要があります。ありがとう。

4

6 に答える 6

16

ええと...run()メソッドは別のスレッドで実行されます。つまり、定義によれば、明示的に同期しない限り、現在のスレッドのどのステートメントが実行されるかについて、どのような仮定もできないことを意味します。

于 2010-04-22T11:14:12.977 に答える
13

run()コード内で新しいスレッドが最初に行うことですが、新しいスレッドが最初に行うセットアップ作業がいくつかあり、元のスレッドが続行する前に新しいスレッドによってかなりの量の作業が行われるという保証はありません。呼び出すdoSomethingElse()

あなたはここに保証がないことを考えているのは正しいです。マルチスレッドコードの動作について推測することは、多くの苦痛の原因です-そうしないようにしてください!

于 2010-04-22T11:12:38.387 に答える
12

さて、私の理解では、start()が呼び出されると、JVMは暗黙的に(そしてすぐに)run()メソッドを呼び出します...

それは正しくありません。暗黙的に呼び出しますrun()が、呼び出しは必ずしもすぐには発生しません。

start()現実には、新しいスレッドは、呼び出しが行われた後のある時点でスケジュールできるようになります。実際のスケジューリングは、ネイティブスケジューラ次第です。すぐに発生するか、親スレッドが子スレッドがスケジュールされる前の期間継続する可能性があります。

スレッドを強制的にすぐに実行を開始するには(より正確には、前に実行を開始するにdoSomethingElse()は)、明示的な同期を行う必要があります。たとえば、次のようなものです。

    java.util.concurrent.CountDownLatch latch = new CountdownLatch(1);
    new Thread(new MyRunnable(latch)).start();
    latch.await(); // waits until released by the child thread.
    doSomethingElse();

どこ

class MyRunnable implements Runnable {
    private CountDownLatch latch;
    MyRunnable (CountDownLatch latch) { this.latch = latch; }
    public void run() {
        doSomeStuff();
        latch.countDown(); // releases the parent thread
        doSomeMoreStuff();
    }
    ...
}

並行性クラス、またはJavaのミューテックス/待機/通知プリミティブ1を使用して同期を実装する他の方法があります。ただし、2つのスレッド間の明示的な同期は、必要な動作を保証する唯一の方法です。

親スレッドが解放される前に子スレッドの呼び出しが完了することに注意してください。ただし、とdoSomething()の実行順序については何も言えません。(一方が他方の前に実行される場合と、その逆の場合があります。または、並行して実行される場合があります。)doSomethingElese()doSomeMoreStuff()


1- wait/の使用notifyはお勧めしませんが、同時実行APIが利用できない場合は、これが唯一のオプションになる可能性があります。たとえば、JavaMEの場合。

于 2010-04-22T11:50:39.270 に答える
6

を呼び出すmyThread.start()と、スレッドが実行可能になります。それが実際にCPUを獲得するかどうか、そしてどのくらいの期間-それはOSスケジューラーにかかっています。実際、あなたrun()はすぐにコントロールを取得しているかもしれませんが、それがあなたが気付くことができる何かをすることができる前にそれを失うこと。スレッドが以前に必要なものを実行することを保証する唯一の方法doSomethingElse()は、明示的な同期を使用することです。

于 2010-04-22T11:19:52.713 に答える
3

新しいスレッドを開始しました。そのスレッドは、それを開始したスレッドと並行して実行されるため、順序は次のようになります。

pObject.run();
doSomethingElse();

また

doSomethingElse();
pObject.run();

または、より可能性が高いのは、いくつかのクロスオーバーがあるでしょう。pObject.run()途中で実行することも、doSomethingElse()その逆の場合もあります。または、一方が終了する前に開始する場合もあります。これを理解し、不可分操作の意味を理解することが重要です。そうしないと、見つけるのが非常に難しいバグに気付くでしょう。

2つ以上のスレッドが同じ変数にアクセスする場合は、さらに複雑になります。特定の状況では、1つの値が1つのスレッドで更新されることはありません。

私は強くお勧めします:

  1. どうしても必要な場合を除いて、プログラムをマルチスレッドにすることはありません。

  2. もしそうなら、BrianGoetzのJavaConcurrency in Practiceをカバーするために、カバーから購入して読んでください。

于 2010-04-22T11:16:32.800 に答える
0

スレッドオブジェクトでstartメソッドを呼び出すと、jvmがrun()メソッドをすぐに呼び出さない場合があります。むしろ、スレッドを実行可能にして実行できるようにします。この場合、親スレッドは最初にコードを実行し、次に制御を子に渡します。スレッド。親スレッドコードが実行される前に子スレッドを実行する場合は、親スレッドでchileThreadObject.join()メソッドを使用します。

于 2018-10-23T23:25:43.410 に答える