Come avviare due thread "esattamente" nello stesso momento


91

I thread dovrebbero iniziare alla stessa frazione di secondo. Capisco, se lo fai thread1.start(), ci vorranno alcuni millisecondi prima della prossima esecuzione di thread2.start().

È anche possibile o impossibile?


2
La frazione di secondo è un tempo molto lungo a velocità GHz.
Nikolai Fetissov

30
Non c'è bisogno di downvote così intensamente. Non tutti capiscono il non determinismo correlato al threading e tutti dobbiamo iniziare da qualche parte.
Michael Petrotta

7
Non capisco i voti negativi. La sincronizzazione tra i thread è una necessità molto comune. Sì in java non è possibile farli eseguire esattamente in parallelo (il che, su altre piattaforme può essere un requisito molto valido tra l'altro), ma di tanto in tanto è molto comune che sia necessario sincronizzare le loro azioni. Ecco perché jdk ha classi per farlo. Forse la formulazione non era accurata, ma diavolo se l'avesse saputo, non avrebbe posto la domanda ..
Enno Shioji

beh, immagino di capire tutta la tua rabbia. Era una domanda che mi veniva posta in un'intervista ... probabilmente era un trucco Q. Ma mi sono solo confuso e volevo confermarlo. ecco perché ho chiesto se fosse possibile.
figaro

2
@javaguy - non una domanda "trucco". Piuttosto una domanda scelta per vedere quanto bene capisci davvero la programmazione multi-thread in generale ... anche nel caso di Java.
Stephen C

Risposte:


135

Per avviare i thread esattamente nello stesso momento (almeno il più bene possibile), puoi utilizzare un 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");

Questo non deve essere un CyclicBarrier, potresti anche usare CountDownLatchao anche un lucchetto.

Questo non è ancora sicuro che vengano avviati esattamente nello stesso momento su JVM standard, ma puoi avvicinarti abbastanza. Avvicinarsi è ancora utile quando si eseguono, ad esempio, test delle prestazioni. Ad esempio, se stai cercando di misurare il throughput di una struttura dati con un numero diverso di thread che la colpiscono, vuoi usare questo tipo di costrutto per ottenere il risultato più accurato possibile.

Su altre piattaforme, l'avvio di thread esattamente può essere un requisito molto valido tra l'altro.


5
+1 bel pensiero ;-) Anche se ovviamente non fa iniziare i thread esattamente nello stesso momento in tempo reale (almeno non su un chip single-core, e non è garantito nemmeno su un chip multi-core), ma Non riesco a pensare a un modo per fare di meglio.
David Z

Questo hook nelle maniglie di attesa specifiche dell'ambiente?
ChaosPandion

@ ChaosPandion: ti interessa elaborare?
Babbo Natale

@Santa - L'API Win32, ad esempio, offre diverse primitive. Un tipo utile è l'evento di ripristino manuale restituito quando si chiama CreateEvent. msdn.microsoft.com/en-us/library/ms686364%28VS.85%29.aspx
ChaosPandion

1
@Zwei - Beh, qualunque cosa sia, questa è la risposta che avrei postato se fossi stato un guru di Java.
ChaosPandion

15

Non è possibile, almeno su un computer single core. Ma perché lo vuoi? Anche se sei stato in grado di avviare due thread esattamente nello stesso secondo, avanzeranno in modo diverso perché la pianificazione non è sotto il tuo controllo.

Modifica: (in risposta ad alcuni commenti) È un requisito perfettamente valido per sincronizzare lo stato o l'avanzamento di più thread ed CyclicBarrierè un ottimo strumento. Ho risposto alla domanda se è possibile avviare più thread esattamente nello stesso momento . CyclicBarriergarantirà che i thread procedano quando sono esattamente nello stato desiderato, ma non garantisce che inizieranno o riprenderanno esattamente nello stesso momento, anche se potrebbe essere abbastanza vicino. Non si fa menzione delle esigenze di sincronizzazione nella domanda.


1
Puoi avvicinarti maledettamente però. Tutto dipende dalle tecniche di sincronizzazione che utilizzi e, ovviamente, dalla presenza di più di 1 cpu o core.
ChaosPandion

L'idea è che questo sia un approccio sbagliato e non dovrebbe essere necessario in un ambiente non difficile in tempo reale, non che sia "abbastanza vicino".
Nikolai Fetissov

1
È anche impossibile perché la pianificazione dei thread Java non offre una precisione al millisecondo.
Stephen C

1
@Zwei - probabilmente puoi ottenere "dannatamente vicino" la maggior parte del tempo su una macchina altrimenti inattiva. Ma se ne hai bisogno tutto il tempo, devi programmare in un linguaggio come il C, su una macchina con supporto in tempo reale nel sistema operativo. Considera inoltre che la JVM potrebbe eseguire un GC completo nella "frazione di secondo" in cui desideri avviare i thread.
Stephen C

1
È un problema di sincronizzazione perfettamente valido. I thread devono inizializzare alcuni dati, assicurarsi che nessuno vada in un'area critica senza un'adeguata convalida. E il fatto che CyclicBerrier sia incluso nel pacchetto simultaneo di javas significa che questo è un problema importante.
Denis Tulskiy

14

Potresti usare un CountDownLatch per questo. Di seguito un esempio. Sebbene t1 e t2 siano avviati, questi thread continuano ad aspettare fino a quando il thread principale conta alla rovescia del latch. Il numero di conto alla rovescia richiesto è indicato nel costruttore. Il latch del conto alla rovescia può essere utilizzato anche per attendere che i thread finiscano l'esecuzione in modo che il thread principale possa procedere ulteriormente (il caso inverso). Questa classe è stata inclusa da 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
    }
}

Questa risposta potrebbe trarre vantaggio da meno boilerplate nell'esempio di codice.
user2418306

6
  1. A quanto ho capito, la JVM delega principalmente questa roba al sistema operativo. Quindi la risposta sarà specifica del sistema operativo.
  2. È chiaramente impossibile su macchine a processore singolo.
  3. È più complicato rispetto a una macchina multiprocessore. Secondo la Relatività della simultaneità , "è impossibile dire in senso assoluto se due eventi si verificano contemporaneamente se questi eventi sono separati nello spazio". Non importa quanto siano vicini i tuoi processori, sono separati nello spazio.
    1. Se puoi accettare la simultaneità relativa, allora è probabilmente più facile simularla usando tecniche discusse in altre risposte.

1
... e anche se assumiamo un inizio simultaneo, ogni thread ha la sua linea temporale, essendo tutti simultanei , ma non necessariamente paralleli, quindi qualunque cosa qualcuno presuma sulla simultaneità dei thread può (sarà) essere nulla nel prossimo nanosecondo (di qualsiasi cronologia) ...
Holger
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.