Quem está chamando o método Java Thread interrupt () se eu não estou?

87

Eu li e reli Simultaneidade Java na prática, li vários tópicos aqui sobre o assunto, li o artigo da IBM Lidando com exceção interrompida e ainda há algo que simplesmente não estou entendendo e que acho que pode ser quebrado dividido em duas questões:

  1. Se eu nunca estou interrompendo outros threads, o que pode disparar uma InterruptedException ?

  2. Se eu nunca estou interrompendo outros threads usando interrupt () (digamos, porque estou usando outros meios para cancelar meus threads de trabalho, como pílulas de veneno e loop de estilo while (! Cancelled) [como explicado em JCIP]), o que que significa uma InterruptedException ? O que devo fazer ao pegar um? Desligar meu aplicativo?

SintaxeT3rr0r
fonte

Respostas:

50

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 Runnableobjetos são executados usando um ExecutorServicee 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 InterruptedExceptionthen? 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 InterruptedExceptionestá 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.

Stephen C
fonte
12

Se você decidir integrar seu código a outras bibliotecas, eles podem chamar interrupt()seu código. por exemplo, se você decidir no futuro executar seu código dentro de um ExecutorService , isso pode forçar um desligamento via interrupt().

Resumindo, eu consideraria não apenas onde seu código está sendo executado agora , mas em que contexto ele pode ser executado no futuro. por exemplo, você vai colocá-lo em uma biblioteca? Um container ? Como outras pessoas o usarão? Você vai reutilizá-lo?

Brian Agnew
fonte
Pensei que apenas shutdownNow chama o método interrupt (). Isso também vale para o desligamento?
Harinder de
9

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 InterruptedExceptionsozinho 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 que Object.notify()faz. Da mesma forma que você verificaria o estado atual após acordar de uma chamada para Object.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.FutureTasktem um isCancelled()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();
}
Øyvind Bakksjø
fonte
3

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.concurrente 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.

Tom Hawtin - tackline
fonte
Olá, Tom, lembro-me do seu nome de cljp;) Bem, precisamente: nunca tive que interromper () para mim mesmo ... A menos que esteja capturando um InterruptedException e precise reafirmar o status interrompido, mas ainda não é 100% claro para mim. Sou novo aqui e estou surpreso com a quantidade de votos positivos e respostas / comentários (tanto corretos quanto errados): obviamente é um assunto que não é trivial ou, pelo menos, não costuma ser bem explicado. Dito isso, graças a todos os posts, estou começando a ter uma imagem mais clara do que está acontecendo :)
SyntaxT3rr0r
3

Você pode aprender isso criando sua própria classe de thread (extensão java.lang.Thread) e interrupt()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();
    }
}
semana
fonte
1

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 .

mangoDrunk
fonte
1

Acho que entendo por que você está um pouco confuso sobre interrupção. Por favor, considere minhas respostas na linha:

Se eu nunca estou interrompendo outros threads, o que pode disparar uma InterruptedException ?

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.

Se eu nunca interromper outros threads usando interrupt () (digamos, porque estou usando outros meios para cancelar meus threads de trabalho, como pílulas de veneno e loop de estilo while (! Cancelado) [como explicado em JCIP]), o que que significa uma InterruptedException? O que devo fazer ao pegar um? Desligar meu aplicativo?

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.

nawazish-stackoverflow
fonte
0

O InterruptedExceptiondiz 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.

Cinza
fonte