Come si uccide un java.lang.Thread
in Java?
ExecutorStatus
riguarda questa domanda: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Come si uccide un java.lang.Thread
in Java?
ExecutorStatus
riguarda questa domanda: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Risposte:
Vedi questa discussione di Sun sul perché si sono deprecatiThread.stop()
. Descrive in dettaglio il motivo per cui si è trattato di un metodo errato e di cosa si dovrebbe fare per bloccare in sicurezza i thread in generale.
Il modo in cui raccomandano è di utilizzare una variabile condivisa come flag che richiede l'arresto del thread in background. Questa variabile può quindi essere impostata da un oggetto diverso che richiede la terminazione del thread.
getConnection()
da java.sql.DriverManager
. Se il tentativo di connessione impiega troppo tempo, provo a terminare il thread corrispondente chiamando Thread.interrupt()
ma non influenza affatto il thread. Il Thread.stop()
funziona tuttavia, anche se l'oracolo dice che non dovrebbe funzionare, se interrupt()
non lo fa. Mi chiedo come farlo funzionare ed evitare l'utilizzo del metodo obsoleto.
Generalmente non ..
Gli chiedi di interrompere qualunque cosa stia facendo usando Thread.interrupt () (collegamento javadoc)
Una buona spiegazione del perché è nel javadoc qui (collegamento java technote)
interrupt()
viene chiamato il metodo? La domanda principale è relativa alla generazione del registro per ogni nuovo thread.
In Java i thread non vengono uccisi, ma l'interruzione di un thread viene eseguita in modo cooperativo . Viene chiesto di terminare il thread e il thread può quindi arrestarsi con grazia.
Spesso volatile boolean
viene utilizzato un campo che il thread controlla e termina periodicamente quando è impostato sul valore corrispondente.
Non userei a boolean
per verificare se il thread dovrebbe terminare . Se si utilizza volatile
come modificatore di campo, funzionerà in modo affidabile, ma se il codice diventa più complesso, poiché utilizza invece altri metodi di blocco all'interno del while
ciclo, potrebbe accadere che il codice non si interrompa affatto o almeno impiega più tempo potrebbe desiderare.
Alcuni metodi della libreria di blocco supportano l'interruzione.
Ogni thread ha già uno stato booleano interrotto e dovresti usarlo. Può essere implementato in questo modo:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Codice sorgente adattato da Java Concurrency in Practice . Poiché il cancel()
metodo è pubblico, puoi consentire a un altro thread di invocare questo metodo come desideri.
Un modo è quello di impostare una variabile di classe e usarla come sentinella.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Impostare una variabile di classe esterna, ovvero flag = true nell'esempio sopra. Impostalo su false per "uccidere" il thread.
volatile
per assicurarsi che funzioni correttamente ovunque. La classe interna non è statica, quindi il flag dovrebbe essere una variabile di istanza. Il flag deve essere cancellato con un metodo di accesso in modo da poter eseguire altre operazioni (come l'interrupt). Il nome "flag" non è descrittivo.
C'è un modo in cui puoi farlo. Ma se hai dovuto usarlo, o sei un cattivo programmatore o stai usando un codice scritto da programmatori cattivi. Quindi, dovresti pensare di smettere di essere un cattivo programmatore o di smettere di usare questo cattivo codice. Questa soluzione è solo per le situazioni in cui NON È NESSUN ALTRO MODO.
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
Thread.stop
anche se è deprecato.
Thread.stop
fa lo stesso ma controlla anche l'accesso e le autorizzazioni. L'uso Thread.stop
è piuttosto ovvio e non ricordo il motivo per cui l'ho usato al Thread.stop0
posto di quello. Forse Thread.stop
non ha funzionato per il mio caso speciale (Weblogic su Java 6). O forse perché Thread.stop
è deprecato e causa un avvertimento.
Voglio aggiungere diverse osservazioni, basate sui commenti accumulati.
Thread.stop()
interromperà un thread se il gestore della sicurezza lo consente.Thread.stop()
è pericoloso. Detto questo, se stai lavorando in un ambiente JEE e non hai il controllo sul codice chiamato, potrebbe essere necessario; vedi Perché Thread.stop è deprecato?stop()
crea un nuovo ThreadDeathError
errore sul thread chiamante e quindi genera tale errore sul thread target . Pertanto, la traccia dello stack è generalmente priva di valore.stop()
verifica con il gestore della sicurezza e quindi chiama stop1()
quelle chiamate stop0()
. stop0()
è un codice nativo.Thread.stop()
non è stato rimosso (ancora), ma è Thread.stop(Throwable)
stato rimosso in Java 11. ( mailing list , JDK-8204243 )Vorrei votare per Thread.stop()
.
Come ad esempio hai un'operazione di lunga durata (come una richiesta di rete). Presumibilmente stai aspettando una risposta, ma può richiedere del tempo e l'utente passa a un'altra interfaccia utente. Questo thread in attesa ora è a) inutile b) potenziale problema perché quando otterrà il risultato, è completamente inutile e innescherà richiamate che possono portare al numero di errori.
Tutto ciò e può eseguire un'elaborazione della risposta che potrebbe essere intensa per la CPU. E tu, come sviluppatore, non puoi nemmeno fermarlo, perché non puoi lanciare if (Thread.currentThread().isInterrupted())
linee in tutto il codice.
Quindi l'incapacità di fermare forzatamente un thread è strano.
Thread.stop()
modo sicuro. Non stai votando Thread.stop()
, stai chiedendo ogni persona che implementa ogni operazione che potrebbe richiedere molto tempo per renderla sicura in modo sicuro. E questa potrebbe essere una buona idea, ma non ha nulla a che fare con l'implementazione Thread.stop()
come modo per richiedere l'aborto sicuro. Ne abbiamo già interrupt
.
stop
.
La domanda è piuttosto vaga. Se intendevi "come faccio a scrivere un programma in modo che un thread smetta di funzionare quando lo voglio", allora varie altre risposte dovrebbero essere utili. Ma se volevi dire "Ho un'emergenza con un server che non posso riavviare in questo momento e ho solo bisogno di un thread particolare per morire, vieni cosa potrebbe", allora hai bisogno di uno strumento di intervento per abbinare strumenti di monitoraggio come jstack
.
A tale scopo ho creato jkillthread . Vedi le sue istruzioni per l'uso.
C'è ovviamente il caso in cui stai eseguendo una specie di codice non completamente affidabile. (Personalmente ho questo consentendo l'esecuzione degli script caricati nel mio ambiente Java. Sì, ci sono campanelli di allarme di sicurezza che suonano ovunque, ma fa parte dell'applicazione.) In questo sfortunato caso, prima di tutto stai semplicemente sperando chiedendo agli autori degli script per rispettare una sorta di segnale booleano run / non-run. L'unico decente fail safe è chiamare il metodo stop sul thread se, per esempio, dura più di un timeout.
Ma questo è semplicemente "decente", e non assoluto, perché il codice potrebbe catturare l'errore ThreadDeath (o qualunque altra eccezione lanciate esplicitamente), e non ripeterlo come dovrebbe fare un thread gentlemanly. Quindi, la linea di fondo è AFAIA, non esiste una sicurezza assoluta.
Non c'è modo di uccidere con garbo un thread.
Puoi provare a interrompere il thread, una strategia comune è quella di utilizzare una pillola di veleno per inviare un messaggio al thread per fermarsi
public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}
}
}
BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);
Generalmente non si uccide, si interrompe o si interrompe un thread (o si verifica se viene interrotto ()), ma si lascia terminare naturalmente.
È semplice. È possibile utilizzare qualsiasi ciclo insieme al metodo (volatile) variabile booleana all'interno del metodo run () per controllare l'attività del thread. Puoi anche tornare dal thread attivo al thread principale per interromperlo.
In questo modo uccidi con garbo un thread :).
I tentativi di terminazione improvvisa del thread sono una cattiva pratica di programmazione ben nota e la prova di una cattiva progettazione dell'applicazione. Tutti i thread nell'applicazione multithread condividono esplicitamente e implicitamente lo stesso stato del processo e sono costretti a cooperare tra loro per mantenerlo coerente, altrimenti l'applicazione sarà soggetta a bug che saranno davvero difficili da diagnosticare. Pertanto, è responsabilità dello sviluppatore fornire una garanzia di tale coerenza attraverso un'attenta e chiara progettazione dell'applicazione.
Esistono due soluzioni principali per le terminazioni dei thread controllati:
Una spiegazione corretta e dettagliata dei problemi relativi alla terminazione dei thread improvvisi, nonché esempi di soluzioni errate e giuste per la terminazione dei thread controllati sono disponibili qui:
Ecco un paio di buone letture sull'argomento:
Non ho interrotto il funzionamento in Android, quindi ho usato questo metodo, funziona perfettamente:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}
"Uccidere un thread" non è la frase giusta da usare. Ecco un modo in cui possiamo implementare il grazioso completamento / uscita del thread su will:
Runnable che ho usato:
class TaskThread implements Runnable {
boolean shouldStop;
public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
System.out.println("Thread has started");
while (!shouldStop) {
// do something
}
System.out.println("Thread has ended");
}
public void stop() {
shouldStop = true;
}
}
La classe scatenante:
public class ThreadStop {
public static void main(String[] args) {
System.out.println("Start");
// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();
// Stop the thread
task.stop();
System.out.println("End");
}
}
Thread.stop è obsoleto, quindi come possiamo interrompere un thread in Java?
Utilizzare sempre il metodo di interruzione e futuro per richiedere la cancellazione
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}
public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}
public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}
public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
}