2つのスレッドを「正確に」同時に開始する方法


91

スレッドは同じスプリット秒で開始する必要があります。あなたがそうした場合thread1.start()、次のの実行までに数ミリ秒かかると思いますthread2.start()

それは可能か不可能か?


2
スプリットセカンドは、GHz速度では非常に長い時間です。
ニコライフェティソフ2010

30
それほど激しく反対投票する必要はありません。スレッド化に関連する非決定性を誰もが理解しているわけではありません。
Michael Petrotta、2010

7
反対票を理解しないでください。スレッド間の同期は非常に一般的な必要性です。はい、Javaではそれらを完全に並行して実行することはできません(他のプラットフォームでは非常に有効な要件になる可能性があります)が、時々、それらのアクションを同期する必要があることは非常に一般的です。そのため、jdkにはそのためのクラスがあります。たぶん..文言は正確ではありませんでしたが、彼はそれを知っているだろうならば地獄は、彼が質問をしていないだろう
Enno塩路

まあ、私はあなたのすべての怒りを理解していると思います。それはインタビューで私に尋ねられた質問でした...おそらくトリックQでした。しかし、私は混乱し、それを確認したかっただけです。だから私はそれが可能かどうか尋ねました。
figaro 2010

2
@javaguy-「トリック」の質問ではありません。むしろ、Javaの場合と同様に、マルチスレッドプログラミング全般をどの程度理解しているかを確認するために選ばれた質問です。
スティーブンC

回答:


135

スレッドをまったく同時に(少なくとも可能な限り)開始するには、CyclicBarrierを使用できます。

// We want to start just 2 threads at the same time, but let's control that 
// timing from the main thread. That's why we have 3 "parties" instead of 2.
final CyclicBarrier gate = new CyclicBarrier(3);

Thread t1 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};
Thread t2 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};

t1.start();
t2.start();

// At this point, t1 and t2 are blocking on the gate. 
// Since we gave "3" as the argument, gate is not opened yet.
// Now if we block on the gate from the main thread, it will open
// and all threads will start to do stuff!

gate.await();
System.out.println("all threads started");

これはである必要はありません。ロックをCyclicBarrier使用することもできCountDownLatchます。

これでも、標準のJVMでそれらが正確に同時に開始されていることを確認することはできませんが、かなり近づくことができます。たとえばパフォーマンステストなどを行う場合は、かなり近づくことも役に立ちます。たとえば、データ構造にヒットするスレッドの数が異なるデータ構造のスループットを測定しようとしている場合、この種の構成を使用して、可能な限り最も正確な結果を取得する必要があります。

他のプラットフォームでは、開始スレッドは正確ところで非常に有効な要求をすることができます。


5
+1いい考え;-)もちろん、スレッドをリアルタイムで正確に同時に開始することはできません(少なくともシングルコアチップではなく、マルチコアチップでも保証されません)。私はもっ​​と良くする方法を考えることができません。
David Z

これは環境固有の待機ハンドルにフックしますか?
ChaosPandion、2010

@ChaosPandion:詳細に注意してください?
サンタ

@Santa-たとえば、Win32 APIはさまざまなプリミティブを提供します。便利なタイプの1つは、を呼び出しCreateEventたときに返される手動リセットイベントです。msdn.microsoft.com/en-us/library/ms686364%28VS.85%29.aspx
ChaosPandion 2010

1
@Zwei-まあ、それが何であれ、これは私がJavaの第一人者だったら投稿したはずの答えです。
ChaosPandion、2010

15

少なくともシングルコアコンピュータでは不可能です。しかし、なぜそれが必要なのですか?2つのスレッドをまったく同じ秒に開始できたとしても、スケジューリングが制御できないため、スレッドの進行は異なります。

編集:(コメントの一部に対応)複数のスレッドの状態または進行状況同期することは完全に有効な要件でCyclicBarrierあり、優れたツールです。複数のスレッドを同時に開始することが可能かどうかという質問に答えました。CyclicBarrierそれらが所望の状態で正確ですが、それは彼らがで開始または再開されることを保証するものではないときのスレッドが進行することが保証されます正確に、それは非常に近いかもしれませんが、同じ時間。質問には同期の必要性についての言及はありません。


1
でもかなり近くまで行くことができます。それはすべて、使用する同期技術に依存し、もちろん1つ以上のCPUまたはコアを持つことになります。
ChaosPandion、2010

この考え方は、これは頭の悪いアプローチであり、ハードリアルタイムではない環境では必要ないはずであり、「かなり近い」ということではありません。
Nikolai Fetissov 2010

1
Javaスレッドのスケジューリングではミリ秒単位の精度が得られないため、これ不可能です。
スティーブンC

1
@Zwei-ほとんどの場合、アイドル状態のマシンでは「くそっと閉じる」ことができます。しかし、常にそれが必要な場合は、OSでハードリアルタイムサポートを備えたマシン上で、Cなどの言語でプログラミングする必要があります。また、JVMがスレッドを開始する「スプリット秒」でフルGCを実行している可能性があることも考慮してください。
スティーブンC

1
これは完全に有効な同期の問題です。スレッドは一部のデータを初期化する必要があります。適切な検証なしに重要な領域に入らないようにしてください。また、CyclicBerrierがjavas並行パッケージに含まれているという事実は、これが重要な問題であることを意味します。
Denis Tulskiy 2010

14

これにはCountDownLatchを使用できます。以下のサンプルを見つけてください。t1とt2が開始されても、これらのスレッドはメインスレッドがラッチをカウントダウンするまで待機し続けます。必要なカウントダウンの数はコンストラクターに記載されています。カウントダウンラッチを使用して、スレッドが実行を完了するのを待機し、メインスレッドをさらに進めることもできます(逆の場合)。このクラスはJava 1.5以降に含まれていました。

import java.util.concurrent.CountDownLatch;


public class ThreadExample
{
    public static void main(String[] args) 
    {
        CountDownLatch latch = new CountDownLatch(1);
        MyThread t1 = new MyThread(latch);
        MyThread t2 = new MyThread(latch);
        new Thread(t1).start();
        new Thread(t2).start();
        //Do whatever you want
        latch.countDown();          //This will inform all the threads to start
        //Continue to do whatever
    }
}

class MyThread implements Runnable
{
    CountDownLatch latch;
    public MyThread(CountDownLatch latch) 
    {
        this.latch = latch;
    }
    @Override
    public void run() 
    {
        try 
        {
            latch.await();          //The thread keeps waiting till it is informed
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Do the actual thing
    }
}

この答えは、コード例のボイラープレートを少なくすることでメリットが得られます。
user2418306

6
  1. 私が理解しているように、JVMはほとんどの場合、これをオペレーティングシステムに委任しています。したがって、答えはOS固有です。
  2. シングルプロセッサマシンでは明らかに不可能です。
  3. マルチプロセッサマシンに関してはより複雑です。同時性の相対性による、「2つのイベントが空間で分離されている場合、2つのイベントが同時に発生するかどうかを絶対的な意味で言うことは不可能です。」プロセッサーがどれほど近くても、それらは空間的に分離されています。
    1. 相対的な同時性を受け入れることができる場合は、他の応答で説明されている手法を使用してそれをシミュレートする方がおそらく簡単です。

1
…同時に開始すると仮定した場合でも、各スレッドには独自のタイムラインがあり、すべてが同時ではありませんが、必ずしも並列であるとは限らないため、スレッドの同時性について誰かが想定することは、次のナノ秒で無効になる可能性がありますタイムライン)…
Holger、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.