O mecanismo de interrupção de thread é a maneira preferida de fazer com que um thread (em cooperação) responda a uma solicitação para interromper o que está fazendo. Qualquer tópico (incluindo o próprio tópico, eu acho) poderia chamar interrupt()
um Tópico.
Na prática, os casos de uso normais para interrupt()
envolvem algum tipo de estrutura ou gerente dizendo a algum thread de trabalho para parar o que está fazendo. Se o thread de trabalho estiver "ciente de interrupção", ele notará que foi interrompido por meio de uma exceção ou verificando periodicamente seu sinalizador de interrupção. Ao perceber que foi interrompido, um fio bem comportado abandonaria o que está fazendo e se encerraria.
Supondo o caso de uso acima, seu código provavelmente será interrompido se for executado dentro de uma estrutura Java ou de algum thread de trabalho. E quando for interrompido, seu código deve abandonar o que está fazendo e fazer com que seja encerrado da maneira mais apropriada. Dependendo de como seu código foi chamado, isso pode ser feito retornando ou lançando alguma exceção apropriada. Mas provavelmente não deveria chamar System.exit()
. (Seu aplicativo não sabe necessariamente por que foi interrompido e certamente não sabe se há outros threads que precisam ser interrompidos pela estrutura.)
Por outro lado, se seu código não foi projetado para ser executado sob o controle de alguma estrutura, você pode argumentar que InterruptedException
é uma exceção inesperada; ou seja, um bug. Nesse caso, você deve tratar a exceção como faria com outros bugs; por exemplo, envolva-o em uma exceção não verificada e capture e registre-o no mesmo ponto em que você lida com outras exceções não verificadas inesperadas. (Alternativamente, seu aplicativo pode simplesmente ignorar a interrupção e continuar fazendo o que estava fazendo.)
1) Se eu nunca estou interrompendo outros threads, o que pode disparar uma InterruptedException?
Um exemplo é se seus Runnable
objetos são executados usando um ExecutorService
e shutdownNow()
são chamados no serviço. E, em teoria, qualquer pool de threads de terceiros ou estrutura de gerenciamento de threads poderia legitimamente fazer algo assim.
2) Se eu nunca interrompo outras threads usando interrupt () ... o que significa um InterruptedException
then? O que devo fazer ao pegar um? Desligar meu aplicativo?
Você precisa analisar a base de código para descobrir o que está fazendo as interrupt()
chamadas e por quê. Depois de descobrir isso, você pode descobrir o que >> sua << parte do aplicativo precisa fazer.
Até que você saiba por que InterruptedException
está sendo lançado, aconselho tratá-lo como um erro grave; por exemplo, imprima um rastreamento de pilha para o arquivo de log e desligue o aplicativo. (Obviamente, nem sempre essa é a resposta certa ... mas a questão é que isso é "um bug" e precisa ser levado ao conhecimento do desenvolvedor / mantenedor.)
3) Como descubro quem / o que está ligando interrupt()
?
Não há uma boa resposta para isso. O melhor que posso sugerir é definir um ponto de interrupção no Thread.interrupt()
e olhar para a pilha de chamadas.
Como outros apontaram, interromper um thread (na verdade, interromper uma chamada de bloqueio) geralmente é usado para fins de saída limpa ou cancelar uma atividade em andamento.
No entanto, você não deve tratar um
InterruptedException
sozinho como um "comando para sair". Em vez disso, você deve pensar nas interrupções como um meio de controlar o status de execução de threads, da mesma forma queObject.notify()
faz. Da mesma forma que você verificaria o estado atual após acordar de uma chamada paraObject.wait()
(você não presume que o despertar significa que sua condição de espera foi satisfeita), depois de ser cutucado com uma interrupção, você deve verificar por que foi interrompido . Geralmente, há uma maneira de fazer isso. Por exemplo,java.util.concurrent.FutureTask
tem umisCancelled()
método.Amostra de código:
public void run() { .... try { .... // Calls that may block. } catch (InterruptedException e) { if (!running) { // Add preferred synchronization here. return; // Explicit flag says we should stop running. } // We were interrupted, but the flag says we're still running. // It would be wrong to always exit here. The interrupt 'nudge' // could mean something completely different. For example, it // could be that the thread was blocking on a read from a particular // file, and now we should read from a different file. // Interrupt != quit (not necessarily). } .... } public void stop() { running = false; // Add preferred synchronization here. myThread.interrupt(); }
fonte
O problema com a pergunta é "eu". "I" geralmente se refere a uma única instância de uma classe. Quero dizer com isso, que qualquer parte específica do código de baixo nível (classe) não deve depender da implementação de todo o sistema. Tendo dito isso, você deve tomar algumas decisões "arquitetônicas" (como em qual plataforma executar).
Possíveis interrupções inesperadas provenientes do JRE são tarefas canceladas
java.util.concurrent
e o encerramento de miniaplicativos.O tratamento de interrupções de thread geralmente é escrito incorretamente. Portanto, sugiro a decisão arquitetônica para evitar causar interrupções sempre que possível. No entanto, as interrupções de tratamento de código sempre devem ser escritas corretamente. Não posso fazer interrupções fora da plataforma agora.
fonte
Você pode aprender isso criando sua própria classe de thread (extensão
java.lang.Thread
) einterrupt()
método de substituição , no qual você grava o rastreamento de pilha em, digamos, um campo String e, em seguida, transfere para super.interrupt ().public class MyThread extends Thread { public volatile String interruptStacktrace; // Temporary field for debugging purpose. @Override public void interrupt() { interruptStacktrace = dumpStack(); // You implement it somehow... super.interrupt(); } }
fonte
Como já mencionado, outra biblioteca pode interromper seus threads. Mesmo que a biblioteca não tenha acesso explícito aos threads de seu código, eles ainda podem obter a lista de threads em execução e interrompê-los dessa forma com o método a seguir .
fonte
Acho que entendo por que você está um pouco confuso sobre interrupção. Por favor, considere minhas respostas na linha:
Em primeiro lugar, você pode interromper outros tópicos; Eu sei que no JCiP é mencionado que você nunca deve interromper threads que você não possui; no entanto, essa declaração deve ser bem compreendida. O que isso significa é que o seu código, que pode estar sendo executado em qualquer thread arbitrário, não deve lidar com a interrupção porque, como não é o proprietário do thread, ele não tem idéia de sua política de interrupção. Portanto, você pode solicitar a interrupção de outros threads, mas deixe seu dono fazer o curso da ação de interrupção; tem a política de interrupção encapsulada dentro dele, não seu código de tarefa; pelo menos seja cortês para definir o sinalizador de interrupção!
Existem muitas maneiras pelas quais ainda pode haver interrupções, pode haver tempos limite, interrupções JVM etc.
Você precisa ter muito cuidado aqui; se você possui o thread que lançou InterruptedException (IE), então você sabe o que fazer ao capturá-lo, digamos que você pode desligar seu aplicativo / serviço ou pode substituir este thread eliminado por um novo! No entanto, se você não possuir o thread, ao capturar o IE, jogue-o novamente para cima na pilha de chamadas ou depois de fazer algo (pode estar registrando), redefina o status interrompido para que o código que possui este thread, quando o controle o atingir aprenda que o encadeamento foi interrompido e, portanto, execute as ações como for necessário, pois somente ele conhece a política de interrupção.
Espero que tenha ajudado.
fonte
O
InterruptedException
diz que uma rotina pode ser interrompida, mas não necessariamente que será.Se você não espera a interrupção, deve tratá-la como faria com qualquer outra exceção inesperada. Se estiver em uma seção crítica onde uma exceção inesperada pode ter consequências hediondas, pode ser melhor tentar limpar os recursos e desligar normalmente (porque receber os sinais de interrupção de que seu aplicativo bem projetado que não depende de interrupções está sendo usado de uma forma que não foi projetado e, portanto, deve haver algo errado). Alternativamente, se o código em questão for algo não crítico ou trivial, você pode ignorar (ou registrar) a interrupção e continuar.
fonte