2009-12-10 11 views
45

Ho difficoltà a trovare un modo per avviare, arrestare e riavviare un thread in Java.Come avviare/arrestare/riavviare un thread in Java?

In particolare, ho una classe Task (attualmente implementa Runnable) in un file Task.java. La mia applicazione principale deve essere in grado di avviare questa attività su un thread, STOP (uccidere) il thread quando necessario, e talvolta KILL & RIAVVIA il thread ...

Il mio primo tentativo è stato con ExecutorService ma posso ' t sembra trovare un modo per riavviare un'attività. Quando uso .shutdownnow() qualsiasi chiamata futura a .execute() non riesce perché il ExecutorService è "shutdown" ...

Quindi, come potrei realizzare questo?

+0

Per questa domanda è anche possibile fare riferimento a: http://stackoverflow.com/questions/22937592/resume-interrupted-thread – artiethenoble

risposta

39

Una volta interrotta una discussione, non è possibile riavviarla. Tuttavia, non c'è nulla che ti impedisca di creare e iniziare un nuovo thread.

Opzione 1: Creare una nuova discussione anziché tentare di riavviarla.

Opzione 2: Invece di lasciare che il thread si arresti, attendere e quindi quando riceve la notifica, è possibile consentirgli di eseguire nuovamente il lavoro. In questo modo il thread non si ferma mai e non dovrà mai essere riavviato.

Modifica sulla base di commento:

di "uccidere" il filo si può fare qualcosa di simile a quanto segue.

yourThread.setIsTerminating(true); // tell the thread to stop 
yourThread.join(); // wait for the thread to stop 
+0

Purtroppo devo uccidere/riavviarlo ... Non ho il controllo completo sui contenuti del thread e per la mia situazione richiede un riavvio ... Quindi, la creazione di una nuova va bene ... ma come faccio a eliminare quella corrente prima? – Shaitan00

+0

Se si vuole veramente "uccidere" il thread non fare mai affidamento o tentare di utilizzare uno qualsiasi dei metodi API che sembrano farlo, ad esempio kill() stop() destroy(). Invece, come suggerito da Taylor, guarda il flag interrotto: while (! Thread.currentThread(). IsInterrupted()) {...} Quando il thread viene interrotto, cancella tutte le funzioni in quel thread e ritorna fuori dal eseguire il metodo e iniziare una nuova discussione. –

+0

Presumo che ci sia un ciclo nella tua discussione in modo che possa controllare un flag per vedere se il thread deve fermarsi o continuare l'esecuzione. –

0

C'è una differenza tra mettere in pausa un thread e fermarlo/ucciderlo. Se fermarsi per te significa uccidere il thread, quindi un riavvio significa semplicemente creare un nuovo thread e lanciare.

Esistono metodi per eliminare i thread da un thread diverso (ad es. Lo spawner), ma in generale non sono sicuri. Potrebbe essere più sicuro se il tuo thread controlla costantemente qualche flag per vedere se dovrebbe continuare (presumo che ci sia del loop nella tua discussione), e avere il "controller" esterno per cambiare lo stato di quel flag.

si può vedere un po 'più in: http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

Posso chiedere perché si vuole uccidere il filo e riavviarlo? Perché non aspettare che i suoi servizi siano nuovamente necessari? Java ha meccanismi di sincronizzazione esattamente per questo scopo. Il thread andrà in sospensione fino a quando il controller non lo notifica per continuare l'esecuzione.

0

Se l'attività esegue un tipo di azione in un ciclo, esiste un modo per mettere in pausa/riavviare l'elaborazione, ma penso che dovrebbe essere al di fuori di ciò che offre attualmente l'API Thread. Se si tratta di un processo a scatto singolo, non sono a conoscenza di alcun modo per sospendere/riavviare senza eseguire API che è stata deprecata o non è più consentita.

Per quanto riguarda i processi in loop, il modo più semplice a cui potrei pensare è che il codice che genera l'attività crea un'istanza di ReentrantLock e lo passa all'attività, oltre a mantenere un riferimento. Ogni volta che l'attività entra nel suo ciclo tenta un blocco sull'istanza ReentrantLock e quando il ciclo completo deve sbloccarsi. Potresti voler incapsulare tutto questo try/finally, assicurandoti di lasciar andare il lock alla fine del ciclo, anche se viene lanciata un'eccezione.

Se si desidera sospendere l'operazione, tentare semplicemente un blocco dal codice principale (poiché è stato mantenuto un riferimento a portata di mano). Ciò che questo farà è attendere il completamento del ciclo e non lasciarlo avviare un'altra iterazione (poiché il thread principale è in possesso di un blocco). Per riavviare il thread è sufficiente sbloccare il codice principale, questo consentirà all'attività di riprendere i suoi loop.

Per interrompere definitivamente il thread, utilizzerei la normale API o lasciare un flag nell'attività e un setter per il flag (qualcosa come stop immediato). Quando il ciclo ha rilevato un valore true per questo flag, interrompe l'elaborazione e completa il metodo di esecuzione.

+0

Purtroppo il thread è in attesa (in ascolto) per il traffico in entrata, si tratta di un evento sincrono di blocco ... quindi non esiste un "loop" – Shaitan00

7

Recensione java.lang.Thread.

per avviare o riavviare (una volta un filo è fermo, non è possibile riavviare lo stesso thread, ma non importa, basta creare una nuova Thread esempio):

// Create your Runnable instance 
Task task = new Task(...); 

// Start a thread and run your Runnable 
Thread t = new Thread(task); 

per fermarlo, avere un metodo sull'istanza Task che imposta un flag per indicare al metodo run di uscire; tornando da run si esce dalla discussione. Se il codice chiamante ha bisogno di sapere il filo in realtà si è fermato prima che ritorni, è possibile utilizzare join:

// Tell Task to stop 
task.setStopFlag(true); 

// Wait for it to do so 
t.join(); 

Per quanto riguarda il riavvio: Anche se una Thread non può essere riavviato, è possibile riutilizzare l'istanza Runnable con una nuova thread se ha stato e tale che vuoi mantenere; che arriva alla stessa cosa Assicurati che il tuo Runnable sia progettato per consentire più chiamate a run.

+0

Purtroppo il thread è in attesa (in ascolto) per il traffico in entrata, si tratta di un evento sincrono di blocco. Quindi non c'è un "loop" all'interno di esecuzione ... – Shaitan00

+2

@ Shaitan00: Se stai parlando di un blocco di 'ServerSocket' su una chiamata' accept', allora hai semplicemente la '' setStopFlag' chiamata 'close' sul socket. La chiamata 'accept' si sbloccherà lanciando un' SocketException'. Qualunque altra cosa blocchi avrà quasi certamente una modalità di uscita analoga. –

1

Come affermato da Taylor L, non è possibile "interrompere" un thread (chiamando un metodo semplice) a causa del fatto che potrebbe lasciare il sistema in uno stato instabile poiché il thread di chiamata esterno potrebbe non sapere cosa sta succedendo all'interno del tuo thread.

Con questo detto, il modo migliore per "fermare" un thread è di avere il thread di tenere d'occhio se stesso e di farlo sapere e capire quando dovrebbe fermarsi.

+0

Ma il thread stesso sta bloccando su un .receive in ascolto per il traffico di rete ... in realtà non loop finché non riceve qualcosa .... Quindi, invia un messaggio fittizio a "kick the loop in marcia" e impostare una bandiera? – Shaitan00

3

Non è possibile riavviare un thread in modo che l'opzione migliore sia salvare lo stato corrente dell'oggetto nel momento in cui il thread è stato interrotto e quando è necessario continuare su quell'oggetto è possibile ricreare quell'oggetto utilizzando il salvataggio e quindi inizia il nuovo thread.

Questi due articoli Swing Worker e Concurrency possono aiutarti a determinare la soluzione migliore per il tuo problema.

+0

@ ChadNC- Questo suona bene. Puoi per favore guidarmi di più su come salvare lo stato attuale dell'oggetto e poi continuare. – user2821894

8

È impossibile terminare un thread a meno che il codice in esecuzione in quel thread non ne consenta la chiusura.

Lei ha detto: "Purtroppo devo uccidere/riavviarlo ... Non ho il controllo completo sui contenuti del filo e per la mia situazione si richiede un riavvio"

Se il contenuto del filo non consente di terminare la sua esecuzione quindi non è possibile terminare quel thread.

Nel tuo post hai detto: "Il mio primo tentativo è stato con ExecutorService, ma io non riesco a trovare un modo per esso riavviare un compito Quando uso .shutdownnow() ...."

Se guarda la fonte di "shutdownnow" che viene appena eseguita e interrompe i thread attualmente in esecuzione.Ciò non interromperà la loro esecuzione a meno che il codice in quei thread controlli per vedere se è stato ineterrupted e, in tal caso, interrompe l'esecuzione stessa. Quindi shutdownnow probabilmente non sta facendo quello che pensi.

Permettetemi di illustrare ciò che intendo quando dico che il contenuto del filo devono consentire quel filo a essere terminato:

myExecutor.execute(new Runnable() { 
public void run() { 
    while (true) { 
    System.out.println("running"); 
    } 
} 
}); 
myExecutor.shutdownnow(); 

Quel filo continuerà a correre per sempre, anche se shutdownnow è stato chiamato, perché non controlla mai per vedere se è stato terminato o meno. Questa discussione, tuttavia, si spegnerà:

myExecutor.execute(new Runnable() { 
public void run() { 
    while (!Thread.interrupted()) { 
    System.out.println("running"); 
    } 
} 
}); 
myExecutor.shutdownnow(); 

Da questa discussione controlla per vedere se è stata interrotta/spegnimento/terminato.

Quindi, se si desidera un thread che è possibile chiudere, è necessario assicurarsi che controlli per vedere se è stato interrotto. Se vuoi un thread che puoi "spegnere" e "riavviare" puoi renderlo eseguibile in grado di svolgere nuovi compiti come menzionato prima.

Perché non si può arrestare un thread in esecuzione? Beh, in realtà ho mentito, puoi chiamare "yourThread.stop()" ma perché è una cattiva idea? Il thread potrebbe essere in una sezione del codice sincronizzata (o altra sezione critica, ma ci limiteremo alle definizioni custodite dalla parola chiave sincronizzata qui) quando la interromperai. i blocchi di sincronizzazione dovrebbero essere eseguiti nella loro interezza e solo da un thread prima di poter accedere ad altri thread. Se si interrompe un thread nel mezzo di un blocco di sincronizzazione, la protezione messa in atto dal blocco di sincronizzazione viene invalidata e il programma si troverà in uno stato sconosciuto. Gli sviluppatori fanno roba messa nei blocchi di sincronizzazione per mantenere le cose sincronizzate, se si usa threadInstance.stop() si distrugge il significato di sincronizzazione, cosa lo sviluppatore di quel codice stava cercando di realizzare e come lo sviluppatore di quel codice si aspettava che i suoi blocchi sincronizzati comportarsi.

-1

Sono completamente in disaccordo con l'affermazione "non si può 'fermare' un thread". È una visione miope su un problema spinoso. Perché?

Controllare regolarmente la bandiera interrotta è in realtà nient'altro che un'altra forma di occupato in attesa con la difficile decisione di "quando controllare la bandiera e con quale frequenza". Può essere molto brutto o impossibile rispondere. Il thread della classe ha anche il metodo "stop (Throwable throwable)" che sfortunatamente è deprecato a ciò che disapprovo profondamente. Dato il metodo run() con il suo corpo in un'istruzione try-catch-finally: Perché è corretto che qualsiasi istruzione (dall'interno del corpo) possa lanciare un'eccezione selezionata o deselezionata mentre una chiamata di stop (new MyRuntimeException ()) dall'esterno non può? È davvero così inaspettato da fuori? Che ne dici di rilanciare RuntimeExceptions inaspettate che sono raramente catturate in quanto spesso sconosciute? Alla fine, le clausole di cattura devono fare i conti con l'eccezione, indipendentemente dall'interno o dall'esterno. E l'ultimo blocco può riordinare. Spero che la gente pensi di nuovo a questo problema di design.

Penso che un thread dovrebbe essere in grado di morire (terminando da solo) o di essere ucciso (terminato immediatamente con un'eccezione).

-1

A volte, se un Thread è stato avviato ed è caricata una classe dinamica rovescio della medaglia, che sta elaborando con un sacco di Thread/currentThread sonno, ignorando interrotto Exception catch (es), un interrupt potrebbe non essere sufficiente per l'esecuzione completamente uscita.

In questo caso, siamo in grado di fornire questi interrupt ciclo-based:

while(th.isAlive()){ 
    log.trace("Still processing Internally; Sending Interrupt;"); 
    th.interrupt(); 
    try { 
     Thread.currentThread().sleep(100); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 
0
You can start a thread like: 

    Thread thread=new Thread(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         //Do you task 
        }catch (Exception ex){ 
         ex.printStackTrace();} 
       } 
      }); 
thread.start(); 

To stop a Thread: 

    thread.join();//it will kill you thread 

    //if you want to know whether your thread is alive or dead you can use 
System.out.println("Thread is "+thread.isAlive()); 

La sua consiglia di creare un nuovo thread, piuttosto che riavviarlo.