So starten Sie zwei Threads „genau“ gleichzeitig

91

Die Threads sollten im gleichen Sekundenbruchteil beginnen. Ich verstehe, wenn Sie dies tun thread1.start(), wird es einige Millisekunden dauern, bis die nächste Ausführung von thread2.start().

Ist es überhaupt möglich oder unmöglich?

figaro
quelle
2
Sekundenbruchteil ist eine sehr lange Zeit bei GHz-Geschwindigkeiten.
Nikolai Fetissov
30
Keine Notwendigkeit, so intensiv abzustimmen. Nicht jeder versteht Threading-bezogenen Nichtdeterminismus, und wir müssen alle irgendwo anfangen.
Michael Petrotta
7
Verstehe die Abstimmungen nicht. Das Synchronisieren zwischen Threads ist eine sehr häufige Notwendigkeit. Ja, in Java können sie nicht exakt parallel ausgeführt werden (was auf einer anderen Plattform übrigens eine sehr gültige Anforderung sein kann), aber von Zeit zu Zeit ist es sehr häufig, dass Sie ihre Aktion synchronisieren müssen. Deshalb hat der JDK Klassen dafür. Vielleicht war der Wortlaut nicht korrekt, aber zur Hölle, wenn er das gewusst hätte, hätte er die Frage nicht gestellt.
Enno Shioji
Nun, ich glaube, ich verstehe all deine Wut. Es war eine Frage, die mir in einem Interview gestellt wurde ... wahrscheinlich war es ein Trick F. Aber ich war nur verwirrt und wollte es bestätigen. deshalb habe ich gefragt, ob es überhaupt möglich ist.
Figaro
2
@javaguy - keine "Trick" -Frage. Eher eine Frage, die ausgewählt wurde, um zu sehen, wie gut Sie die Multithread-Programmierung im Allgemeinen wirklich verstehen ... auch im Java-Fall.
Stephen C

Antworten:

135

Um die Threads genau zur gleichen Zeit zu starten (mindestens so gut wie möglich), können Sie einen CyclicBarrier verwenden :

// 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");

Dies muss kein a sein CyclicBarrier, Sie können auch ein CountDownLatchoder sogar ein Schloss verwenden.

Dies kann immer noch nicht sicherstellen, dass sie auf Standard-JVMs genau zur gleichen Zeit gestartet werden , aber Sie können ziemlich nah dran sein. Wenn Sie beispielsweise Leistungstests durchführen, ist es immer noch nützlich, sich ganz nah zu kommen. Wenn Sie beispielsweise versuchen, den Durchsatz einer Datenstruktur mit einer unterschiedlichen Anzahl von Threads zu messen, möchten Sie diese Art von Konstrukt verwenden, um ein möglichst genaues Ergebnis zu erzielen.

Auf anderen Plattformen beginnen Threads genau können btw eine sehr gültige Anforderung sein.

Enno Shioji
quelle
5
+1 nettes Denken ;-) Obwohl es natürlich nicht dazu führt, dass die Threads in Echtzeit genau zur gleichen Zeit starten (zumindest nicht auf einem Single-Core-Chip und nicht einmal auf einem Multi-Core-Chip garantiert), aber Ich kann mir keinen besseren Weg vorstellen.
David Z
Wird dies in umgebungsspezifische Wartegriffe eingebunden?
ChaosPandion
@ChaosPandion: Möchtest du das näher erläutern?
Santa
@ Santa - Die Win32-API bietet beispielsweise verschiedene Grundelemente. Ein nützlicher Typ ist das manuelle Rücksetzereignis, das beim Aufruf zurückgegeben wird CreateEvent. msdn.microsoft.com/en-us/library/ms686364%28VS.85%29.aspx
ChaosPandion
1
@Zwei - Nun, was auch immer es ist, dies ist die Antwort, die ich gepostet hätte, wenn ich ein Java-Guru gewesen wäre.
ChaosPandion
15

Zumindest auf einem Single-Core-Computer ist dies nicht möglich. Aber warum willst du das? Selbst wenn Sie zwei Threads genau in derselben Sekunde starten konnten, werden sie unterschiedlich ausgeführt, da die Planung nicht in Ihrer Kontrolle liegt.

Bearbeiten: (als Antwort auf einige der Kommentare) Es ist eine absolut gültige Anforderung, den Status oder den Fortschritt mehrerer Threads zu synchronisieren, und es CyclicBarrierist ein großartiges Werkzeug. Ich habe die Frage beantwortet, ob es möglich ist, mehrere Threads genau gleichzeitig zu starten . CyclicBarriergarantiert, dass die Threads fortgesetzt werden, wenn sie sich genau im gewünschten Zustand befinden, garantiert jedoch nicht, dass sie genau zur gleichen Zeit gestartet oder fortgesetzt werden, obwohl dies möglicherweise ziemlich eng ist. In der Frage werden keine Synchronisationsanforderungen erwähnt.

Samitgaur
quelle
1
Sie können aber verdammt nahe kommen. Es hängt alles von den verwendeten Synchronisationstechniken ab und natürlich von mehr als 1 CPU oder Kern.
ChaosPandion
Die Idee ist, dass dies ein falscher Ansatz ist und in einer nicht harten Echtzeitumgebung nicht notwendig sein sollte, nicht dass er "ziemlich nah" ist.
Nikolai Fetissov
1
Dies ist auch nicht möglich, da die Java-Thread-Planung keine Millisekundengenauigkeit bietet.
Stephen C
1
@Zwei - Sie können wahrscheinlich die meiste Zeit auf einer ansonsten inaktiven Maschine "verdammt nah" kommen. Wenn Sie es jedoch ständig benötigen, müssen Sie in einer Sprache wie C auf einem Computer mit starker Echtzeitunterstützung im Betriebssystem programmieren. Bedenken Sie auch, dass die JVM möglicherweise in dem "Sekundenbruchteil", in dem Sie Ihre Threads starten möchten, einen vollständigen GC ausführt.
Stephen C
1
Es ist ein vollkommen gültiges Synchronisationsproblem. Threads müssen einige Daten initialisieren und sicherstellen, dass niemand ohne ordnungsgemäße Validierung in einen kritischen Bereich gelangt. Und die Tatsache, dass CyclicBerrier im gleichzeitigen Paket von javas enthalten ist, bedeutet, dass dies ein wichtiges Problem ist.
Denis Tulskiy
14

Sie können hierfür einen CountDownLatch verwenden. Nachfolgend finden Sie ein Beispiel. Obwohl t1 und t2 gestartet werden, warten diese Threads so lange, bis der Haupt-Thread die Verriegelung herunterzählt. Die Anzahl der erforderlichen Countdowns wird im Konstruktor angegeben. Der Countdown-Latch kann auch verwendet werden, um zu warten, bis die Ausführung der Threads abgeschlossen ist, damit der Haupt-Thread weiter fortfahren kann (im umgekehrten Fall). Diese Klasse wurde seit Java 1.5 aufgenommen.

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
    }
}
aNisch
quelle
Diese Antwort könnte von weniger Boilerplate im Codebeispiel profitieren.
user2418306
6
  1. Soweit ich weiß, delegiert die JVM dieses Material hauptsächlich an das Betriebssystem. Die Antwort wird also betriebssystemspezifisch sein.
  2. Auf Einzelprozessormaschinen ist dies eindeutig unmöglich.
  3. Es ist komplizierter in Bezug auf eine Multiprozessor-Maschine. Nach der Relativität der Gleichzeitigkeit "ist es unmöglich, im absoluten Sinne zu sagen, ob zwei Ereignisse gleichzeitig auftreten, wenn diese Ereignisse im Raum getrennt sind." Egal wie nah Ihre Prozessoren sind, sie sind räumlich getrennt.
    1. Wenn Sie relative Gleichzeitigkeit akzeptieren können, ist es wahrscheinlich einfacher, sie nur mit Techniken zu simulieren, die in anderen Antworten beschrieben werden.
Emory
quelle
1
… Und selbst wenn wir von einem gleichzeitigen Start ausgehen, hat jeder Thread seine eigene Zeitachse, die alle gleichzeitig , aber nicht unbedingt parallel sind. Was auch immer jemand von der Gleichzeitigkeit von Threads annimmt, kann (wird) in der nächsten Nanosekunde (von welcher auch immer) ungültig sein Zeitleiste)…
Holger