2013-06-18 25 views
7

I thread n sono in esecuzione in parallelo e ognuno di essi esegue una logica personalizzata. Tuttavia, il mio requisito è che quando uno qualsiasi dei thread termina l'esecuzione, tutti gli altri thread dovrebbero interrompere l'esecuzione e restituire.Comunicazione tra thread java: interruzione di tutti i thread quando si termina l'attività

Qual è il modo migliore per implementarlo? Ho pensato di farlo con una variabile booleana condivisa. Quando uno qualsiasi dei thread termina l'esecuzione, imposterà il valore booleano. Tutti i thread leggono periodicamente questa variabile e escono se è impostata.

Inoltre, la mia logica personalizzata è un ciclo infinito e, non appena so che altri thread hanno terminato l'esecuzione, voglio interrompere l'esecuzione dopo l'iterazione corrente.

Qual è il modo corretto di farlo?

+0

possibile duplicato di [inter thread communication in java] (http://stackoverflow.com/questions/2170520/inter-thread-communication -in-java) –

+0

Genera tutti gli altri fili da quel filo speciale !!!! – NINCOMPOOP

+0

@ AndersR.Bystrup Non sono convinto che sia un ottimo duplicato, in realtà non risponde a questa domanda. –

risposta

8

Utilizzare un ExecutorService e il suo metodo .invokeAny() (nota: esiste anche una versione con un timeout).

Dal Javadoc:

esegue i compiti assegnati, restituendo il risultato di uno che ha completato con successo (cioè, senza gettare un'eccezione), se c'è ne.

Uno ha il risultato, .shutdown() l'esecutore.

Vedere Executors class per ottenere un executor che si adatta alle vostre esigenze.

Un'altra soluzione è la classe ExecutorCompletionService; in questo caso avresti .take() anziché .invokeAny() e dovresti inviare ciascuna attività una alla volta. E dovresti anche mantenere un riferimento al tuo ExecutorService poiché ne hai bisogno come argomento, e devi anche spegnerlo.

(nota: se non restituire un risultato, fare Callable<Void> casi)

+0

Grazie fge. ExecutorCompletionService farà affidamento su Future.Cancel e interromperà solo se il thread è in attesa di qualcosa. Ora nel mio caso d'uso, ho un ciclo infinito e voglio smettere di eseguire non appena viene eseguita l'iterazione corrente. Nel mio caso d'uso, non va bene se le iterazioni avvengono anche dopo l'annullamento. – shadowfax

+0

Come funziona invokeAny(), si basa anche su interrupt? – shadowfax

+0

Cosa intendi per "fare affidamento sull'interruzione"? – fge

0

io preferirei usare un semaforo comune per controllare l'esecuzione, e avere un controllo frequente nei fili.

public class MyTask implements Runnable { 
    private static volatile boolean isDone = false 
    @Override 
    public void run() { 
     while(true) { 
      if (isDone) { 
       break; 
      } 

      // do some calculation, no wait() s 

      if (...has result...) { 
       isDone = true; 
       break; 
      } 
     } 
    } 
} 

Thread t1 = new Thread(new MyTask()); 
Thread t2 = new Thread(new MyTask()); 
Thread t3 = new Thread(new MyTask()); 
t1.start(); 
t2.start(); 
t3.start(); 

L'unica cosa che si deve essere consapevoli è la variabile static volatile boolean. Statico poiché è necessario accedere allo stesso flag da tutti i thread, volatile per impedire alla JVM di memorizzare nella cache i propri dati. Se non lo contrassegnate come volatile, il compilatore potrebbe produrre un tale codice byte che ottimizzerebbe lo leggendo da un campo in modo tale che legge il campo solo una volta e utilizza il valore salvato per ogni esecuzione del ciclo.

Se le attività sono diverse e si implementano cicli diversi, è possibile utilizzare qualsiasi campo esterno public static volatile boolean per contenere il flag.

Questa soluzione non dipende da su attendere stato del thread. Puoi controllare isDone più punti del tuo loop (anche prima di ogni blocco di codice). Se si garantisce che il codice raggiunga un controllo di uscita, non è comunque necessario interrompere i thread.

0

Guardare, è possibile mantenere su un array globale condiviso tutti gli oggetti Thread, quindi alla fine di ogni attività è possibile eseguire una chiamata a una funzione "cleanup" che prende solo tutti questi oggetti ed esegue una chiamata a "interrupt" " su di essi. Ciò farebbe terminare il primo thread per completare l'esecuzione del resto.

public class MyMain 
{ 
    public static Thread workers[NUM_WORK]; 
    public static void main(..) 
    { 
     MyMain.workers[0] = new Thread(new MyTask0()); 
     . 
     . 
     . 
     MyMain.workers[n] = new Thread(new MyTaskN()); 
     //Then start them all.. 
     // And wait for them unless you want them to die before execution ;) 
    } 
} 

Poi su altri lavoratori

import MyMain; 
public class MyTaskI implements Runnable 
{ 
    public void run() 
    { 
     //Do all the work 
     for(Thread t : MyMain.workers) 
     { 
     // If it is not this thread 
     t.interrupt(); 
     } 
    } 
} 

scusa se ho fatto errori di sintassi. È passato un po 'di tempo da quando ho realizzato Java, l'idea è che hai capito il motivo;)

+0

Come indicato dall'OP, 'thread.interrupt()' si basa sullo stato 'wait'. Se il thread ** non sta aspettando ** su qualcosa, questa soluzione non funzionerà. – gaborsch

+0

Quindi è possibile eseguire un'attesa temporizzata minima all'inizio di ogni iterazione. Se non c'è molto lavoro da fare su ciascun ciclo, allora il ritardo non dovrebbe essere un problema. – cgledezma

Problemi correlati