Como você mata um java.lang.Thread
em Java?
ExecutorStatus
essa questão: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Como você mata um java.lang.Thread
em Java?
ExecutorStatus
essa questão: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Respostas:
Veja este tópico da Sun sobre por que eles foram reprovadosThread.stop()
. Ele entra em detalhes sobre por que esse foi um método ruim e o que deve ser feito para parar com segurança os encadeamentos em geral.
A maneira que eles recomendam é usar uma variável compartilhada como um sinalizador que solicita que o encadeamento em segundo plano pare. Essa variável pode então ser definida por um objeto diferente solicitando o encerramento do encadeamento.
getConnection()
de java.sql.DriverManager
. Se a tentativa de conexão demorar muito, eu tento eliminar o segmento correspondente chamando, Thread.interrupt()
mas ele não influencia o segmento. As Thread.stop()
obras, no entanto, embora a Oracle diga que não deve funcionar se não funcionar interrupt()
. Gostaria de saber como fazê-lo funcionar e evitar o uso de método obsoleto.
Geralmente você não ..
Você pede para interromper o que está fazendo usando Thread.interrupt () (link javadoc)
Uma boa explicação do porquê está no javadoc aqui (link do java technote)
interrupt()
método é chamado? A principal questão está relacionada à geração de logs para cada novo thread.
No Java, os encadeamentos não são eliminados, mas a parada de um encadeamento é feita de maneira cooperativa . É solicitado que o encadeamento seja encerrado e, em seguida, o encadeamento pode ser encerrado normalmente.
Freqüentemente um volatile boolean
, é usado campo que o thread verifica e finaliza periodicamente quando é definido com o valor correspondente.
Eu não usaria a boolean
para verificar se o segmento deve terminar . Se você usar volatile
como um modificador de campo, isso funcionará de maneira confiável, mas se o seu código se tornar mais complexo, pois, em vez disso, usa outros métodos de bloqueio dentro do while
loop, pode acontecer que o código não seja finalizado ou pelo menos demore mais enquanto você posso querer.
Certos métodos de biblioteca de bloqueio suportam interrupção.
Cada encadeamento já possui um status booleano interrompido e você deve fazer uso dele. Pode ser implementado assim:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Código fonte adaptado do Java Concurrency in Practice . Como o cancel()
método é público, você pode permitir que outro thread invoque esse método como desejar.
Uma maneira é definir uma variável de classe e usá-la como sentinela.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Defina uma variável de classe externa, ou seja, flag = true no exemplo acima. Defina como false para 'matar' o thread.
volatile
para garantir que funcione corretamente em qualquer lugar. A classe interna não é estática, portanto, o sinalizador deve ser uma variável de instância. O sinalizador deve ser limpo em um método acessador para que outras operações (como interrupção) possam ser executadas. O nome "flag" não é descritivo.
Existe uma maneira de fazer isso. Mas se você tivesse que usá-lo, você é um programador ruim ou está usando um código escrito por programadores ruins. Portanto, você deve parar de ser um programador ruim ou parar de usar esse código incorreto. Esta solução é apenas para situações em que NÃO HÁ OUTRA MANEIRA.
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
mesmo que seja preterido.
Thread.stop
faz o mesmo, mas também verifica o acesso e as permissões. O uso Thread.stop
é bastante óbvio, e não me lembro do motivo pelo qual usei em Thread.stop0
vez disso. Talvez Thread.stop
não tenha funcionado no meu caso especial (Weblogic em Java 6). Ou talvez porque Thread.stop
esteja obsoleto e cause aviso.
Quero acrescentar várias observações, com base nos comentários acumulados.
Thread.stop()
interromperá um encadeamento se o gerenciador de segurança permitir.Thread.stop()
é perigoso. Dito isto, se você estiver trabalhando em um ambiente JEE e não tiver controle sobre o código que está sendo chamado, pode ser necessário; consulte Por que o Thread.stop foi descontinuado?stop()
cria um novo ThreadDeathError
erro no segmento de chamada e lança esse erro no segmento de destino . Portanto, o rastreamento da pilha geralmente não vale nada.stop()
verifica com o gerenciador de segurança e depois chama as stop1()
chamadas stop0()
. stop0()
é um código nativo.Thread.stop()
não foi removido (ainda), mas Thread.stop(Throwable)
foi removido no Java 11. ( lista de discussão , JDK-8204243 )Eu votaria em Thread.stop()
.
Por exemplo, você tem uma operação duradoura (como uma solicitação de rede). Supostamente, você está aguardando uma resposta, mas isso pode levar tempo e o usuário navegou para outra interface do usuário. Esse encadeamento em espera agora é a) inútil b) problema em potencial porque quando ele obtém resultado, é completamente inútil e ele aciona retornos de chamada que podem levar a vários erros.
Tudo isso e ele pode fazer um processamento de resposta que pode ser intenso na CPU. E você, como desenvolvedor, não pode nem pará-lo, porque você não pode jogarif (Thread.currentThread().isInterrupted())
linhas em todo o código.
Portanto, a incapacidade de forçar a parada de um fio é estranho.
Thread.stop()
com segurança de qualquer maneira. Você não está votando Thread.stop()
, está pedindo a todas as pessoas que implementam todas as operações que podem levar muito tempo para torná-las abortáveis com segurança. E isso pode muito bem ser uma boa idéia, mas não tem nada a ver com a implementação Thread.stop()
como forma de solicitar o aborto seguro. Já temos interrupt
para isso.
stop
.
A questão é bastante vaga. Se você quis dizer "como eu escrevo um programa para que um thread pare de funcionar quando eu quero", várias outras respostas devem ser úteis. Mas se você quis dizer “Eu tenho uma emergência com um servidor, não posso reiniciar agora e só preciso de um encadeamento específico para morrer, aconteça o que acontecer”, então você precisará de uma ferramenta de intervenção para combinar com ferramentas de monitoramento como essa jstack
.
Para esse fim, criei jkillthread . Veja suas instruções de uso.
É claro que existe o caso em que você está executando algum tipo de código não totalmente confiável. (Eu pessoalmente tenho isso ao permitir que scripts enviados sejam executados no meu ambiente Java. Sim, há um alarme de segurança tocando em todos os lugares, mas faz parte do aplicativo.) respeitar algum tipo de sinal booleano de execução / não execução. Seu único segurança decente contra falhas é chamar o método stop no encadeamento se, por exemplo, ele for executado por mais tempo do que o tempo limite.
Mas isso é apenas "decente", e não absoluto, porque o código pode pegar o erro ThreadDeath (ou qualquer exceção que você lançar explicitamente) e não repeti-lo novamente como um encadeamento cavalheiro deve fazer. Portanto, a linha inferior é AFAIA, não existe segurança absoluta contra falhas.
Não há como matar um fio normalmente.
Você pode tentar interromper o thread, uma estratégia comum é usar uma pílula venenosa para fazer com que o thread pare
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”);
Geralmente, você não mata, para ou interrompe um segmento (ou verifica se ele foi interrompido ()), mas deixa que ele termine naturalmente.
É simples Você pode usar qualquer loop junto com a variável booleana (volátil) dentro do método run () para controlar a atividade do encadeamento. Você também pode retornar do thread ativo para o thread principal para pará-lo.
Dessa forma, você normalmente mata um fio :).
Tentativas de término abrupto de encadeamento são práticas ruins de programação bem conhecidas e evidências de um design de aplicativo ruim. Todos os threads no aplicativo multithread explicitamente e implicitamente compartilham o mesmo estado do processo e são forçados a cooperar entre si para mantê-lo consistente; caso contrário, seu aplicativo estará sujeito a erros que serão realmente difíceis de diagnosticar. Portanto, é responsabilidade do desenvolvedor fornecer uma garantia dessa consistência por meio do design cuidadoso e claro do aplicativo.
Existem duas soluções corretas principais para as terminações de threads controladas:
Uma explicação boa e detalhada dos problemas relacionados ao encerramento abrupto de threads, bem como exemplos de soluções erradas e corretas para o encerramento controlado de threads, podem ser encontrados aqui:
Aqui estão algumas boas leituras sobre o assunto:
Como a interrupção não funcionou no Android, usei esse método, funciona perfeitamente:
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;
}
'Matar um fio' não é a frase certa para usar. Aqui está uma maneira de implementar a graciosa conclusão / saída do encadeamento no vontade:
Executável que eu usei:
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;
}
}
A classe acionadora:
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 está obsoleto. Como podemos parar um thread em java?
Sempre use o método de interrupção e o futuro para solicitar o cancelamento
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);
}
}
};
}
}