Handling InterruptedException in Java

Qual é a diferença entre as seguintes formas de manipulação InterruptedException? Qual é a melhor maneira de o fazer?

try{
 //...
} catch(InterruptedException e) { 
   Thread.currentThread().interrupt(); 
}

ou

try{
 //...
} catch(InterruptedException e) {
   throw new RuntimeException(e);
}

EDIT: também gostaria de saber em que cenários são usados estes dois.

Author: Nathan Hughes, 2010-10-20

7 answers

Provavelmente veio fazer esta pergunta porque chamou um método que lança.

Em primeiro lugar, você deve ver {[[4]} para o que é: uma parte da assinatura do método e um possível resultado de chamar o método que você está chamando. Então comece por abraçar o fato de que um InterruptedException é um resultado perfeitamente válido do método call.

Agora, se o método que estás a chamar abre uma excepção, qual deve ser o teu método? Você pode descobrir a resposta por pensando no seguinte:

Faz sentido para o método que estás a implementar para lançar um?Dito de outra forma, será um resultado sensato ao chamar o seu método?

  • Se sim , então throws InterruptedException deve fazer parte de a assinatura do seu método, e deve deixar a excepção propagar-se (ou seja, não a apanhe de todo).

    Exemplo: O seu método espera por um valor da rede para terminar o cálculo e retornar um resultado. Se a chamada de rede de bloqueio lançar um InterruptedException o seu método não consegue terminar a computação de uma forma normal. Deixaste o InterruptedException propagar-se.

    int computeSum(Server server) throws InterruptedException {
        // Any InterruptedException thrown below is propagated
        int a = server.getValueA();
        int b = server.getValueB();
        return a + b;
    }
    
  • Se não, então você não deve declarar o seu método com throws InterruptedException e você deve (deve!) apanhar a excepção. Agora duas coisas são importantes para ter em mente nesta situação:

    1. Alguém interrompeu o teu fio. Esse alguém provavelmente está ansioso para cancelar a operação, terminar o programa graciosamente, ou o que quer que seja. Devias ser educado com essa pessoa e voltar do teu método sem mais demoras.

    2. Mesmo que o seu método consiga produzir um valor de retorno sensato no caso de um InterruptedException o facto de o fio ter sido interrompido pode ainda ser importante. Em particular, o código que chama o seu método pode estar interessado em saber se uma interrupção ocorreu durante a execução do seu método. Você deve, portanto, registar o facto de ter ocorrido uma interrupção, assinalando a interrupção: Thread.currentThread().interrupt()

    Exemplo: O utilizador pediu para imprimir uma soma de dois valores. A impressão "Failed to compute sum " é aceitável se a soma não puder ser calculada (e muito melhor do que deixar o programa estoirar com um traço de pilha devido a um InterruptedException). Por outras palavras, não faz sentido declarar este método comthrows InterruptedException.

    void printSum(Server server) {
         try {
             int sum = computeSum(server);
             System.out.println("Sum: " + sum);
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();  // set interrupt flag
             System.out.println("Failed to compute sum");
         }
    }
    
Por esta altura já devia estar claro que só fazer é uma má ideia. Não é muito educado com quem ligou. Você poderia inventar uma nova exceção de tempo de execução, mas a causa raiz (alguém quer que a linha para parar a execução) pode se perder.

Outros exemplos:

Execução Runnable: Como você pode ter descoberto, a assinatura de Runnable.run não permite a derrubada InterruptedExceptions. Bem, Você inscreveu-se na implementação Runnable, o que significa que Você se inscreveu para lidar com possível InterruptedExceptions. Escolha uma interface diferente, como Callable, ou seguir a segunda abordagem acima.

 

A chamar Thread.sleep: está a tentar ler um ficheiro e o espectrómetro diz que deve tentar 10 vezes com um segundo no meio. Liga-me. Então, tens de lidar com o InterruptedException. Para um método como tryToReadFile faz todo o sentido dizer, " Se sou interrompido, não posso completar a minha acção de tentar ler o file " . Por outras palavras, faz todo o sentido que o método lance.

String tryToReadFile(File f) throws InterruptedException {
    for (int i = 0; i < 10; i++) {
        if (f.exists())
            return readFile(f);
        Thread.sleep(1000);
    }
    return null;
}

Este post foi reescrito como um artigo aqui.
 298
Author: aioobe, 2016-11-28 12:23:39
Por acaso, estava a ler sobre esta manhã, a caminho do trabalho em Java Concurreency, na prática, de Brian Goetz. Basicamente, ele diz que deves fazer uma de duas coisas.
  1. Propagar a InterruptedException - Declare o seu método de jogar o verificado {[[0]} para que o seu chamador tem que lidar com ele.

  2. Repor a interrupção - por vezes não consegue atirar InterruptedException. Nestes casos, deve apanhar o {[[0]} e restaurar o interromper o estado chamando o método interrupt() No currentThread para que o código mais alto da pilha de chamadas possa ver que foi emitida uma interrupção.

 73
Author: mR_fr0g, 2014-02-24 13:04:54
O que estás a tentar fazer?

O {[[0]} é lançado quando um fio está à espera ou a dormir e outro fio interrompe-o usando o método interrupt na classe Thread. Então, se você pegar esta exceção, significa que o fio foi interrompido. Normalmente não faz sentido voltar a chamar Thread.currentThread().interrupt();, a menos que queira verificar o estado "interrompido" do tópico de outro lugar.

Em relação à tua outra opção de lançar um RuntimeException, não parece uma coisa muito sábia de fazer (quem vais apanhar isto? como será tratado?) mas é difícil dizer mais sem informações adicionais.

 16
Author: Grodriguez, 2010-10-20 09:30:24

Para mim a coisa chave sobre isso é: uma interrupção da percepção não é nada que vai errado, é o tópico fazendo o que você lhe disse para fazer. Por isso, derrubá-lo embrulhado numa conceção rústica não faz sentido.

Em muitos casos, faz sentido repensar uma excepção embrulhada numa ideia errónea quando dizes que não sei o que correu mal aqui e não posso fazer nada para o corrigir, só quero que saia do fluxo de processamento actual e bata em qualquer excepção à escala da aplicação. tenho um encarregado para o registar. Esse não é o caso com uma interrupção da percepção, é apenas o tópico que responde a ter a interrupção() chamada sobre ela, está lançando a interrupção da percepção, a fim de ajudar a cancelar o processamento da thread em tempo hábil.

Então propaga a interrupção da percepção, ou come-a inteligentemente (ou seja, num lugar onde terá realizado o que estava destinado a fazer) e repõe a bandeira de interrupção. Note que a bandeira de interrupção é limpa quando o O conceito interrompido é jogado; a suposição que os desenvolvedores da Biblioteca Jdk fazem é que pegar a exceção equivale a lidar com ela, então por padrão a bandeira é limpa.

Então definitivamente a primeira maneira é melhor, o segundo exemplo postado na pergunta não é útil a menos que você não espere que o tópico seja realmente interrompido, e interrompê-lo equivale a um erro.

Eis uma resposta que escrevi descrevendo como as interrupções funcionam, com um exemplo . Você pode ver no exemplo de código onde ele está usando o conceito interrompido para sair de um laço while no método de execução Runnable.

 11
Author: Nathan Hughes, 2017-05-23 11:54:40

A escolha por omissão correcta é adicionar uma excepção interrompida à sua lista de lances. Uma interrupção indica que outro tópico deseja que o seu tópico termine. A razão para este pedido não é evidente e é inteiramente contextual, então se você não tem nenhum conhecimento adicional você deve assumir que é apenas um desligamento amigável, e qualquer coisa que evite esse desligamento é uma resposta não amigável.

O Java não irá lançar aleatoriamente os Interruptedexception's, todos os conselhos não irão afectar a sua aplicação mas eu encontrei um caso em que o desenvolvedor está seguindo a estratégia "swallow" tornou-se muito inconveniente. Uma equipe desenvolveu um grande conjunto de testes e usou Thread.Dorme muito. Agora começamos a executar os testes em nosso servidor CI, e às vezes devido a defeitos no código ficaria preso em espera permanente. Para piorar a situação, ao tentar cancelar o trabalho de CI nunca fechou porque o tópico.Interromper que foi destinado a abortar o teste não abortou o trabalho. Nós tínhamos para entrar na caixa e matar manualmente os processos.

Resumindo, se simplesmente lançar a ideia interrompida, estará a corresponder à intenção predefinida que o seu tópico deverá terminar. Se não puder adicionar uma suspensão à sua lista de lançamento, eu embrulhá-la-ia numa solução rápida.

Há um argumento muito racional a ser feito de que a interrupção da excepção deve ser uma sugestão de execução em si, uma vez que isso encorajaria um melhor tratamento "padrão". Não é uma ideia errada. só porque os designers se agarraram a uma regra categórica de que uma percepção Runtimeexpressiva deve representar um erro no seu código. Uma vez que uma interrupção da percepção não surge diretamente de um erro em seu código, não é. Mas a realidade é que muitas vezes surge uma percepção interrompida porque há um erro em seu código, (ou seja, laço infinito, bloqueio morto), e a interrupção é o método de algum outro thread para lidar com esse erro.

Se sabes que há uma limpeza racional a fazer, fá-lo. Se você conhece uma causa mais profunda para a interrupção, você pode assumir um tratamento mais abrangente.

Por isso, em resumo, as suas escolhas de manipulação devem seguir esta lista:

  1. por omissão, adicione aos lançamentos.
  2. Se não for permitido adicionar aos arremessos, lance o RuntimeException (e). (melhor escolha de várias opções más)
  3. só quando se conhece uma causa explícita da interrupção, manejar como desejado. Se a sua manipulação é local para o seu método, em seguida, reiniciado interrompido por uma chamada roscar.currentThread().interromper().
 6
Author: nedruod, 2013-09-20 21:32:50
Só queria acrescentar uma última opção ao que a maioria das pessoas e artigos mencionam. Como o mR_fr0g afirmou, É importante lidar com a interrupção corretamente por:
  • Propagação da interrupção

  • Repor o estado de interrupção no tópico

Ou adicionalmente:

  • Tratamento Personalizado da interrupção

Não há nada de errado em lidar com a interrupção de uma forma personalizada, dependendo das suas circunstâncias. Como um interromper é um pedido de terminação, ao contrário de um comando forçoso, é perfeitamente válido para completar o trabalho adicional para permitir que a aplicação para lidar com o pedido graciosamente. Por exemplo, se um fio está dormindo, esperando IO ou uma resposta de hardware, quando recebe a interrupção, então é perfeitamente válido para graciosamente fechar quaisquer conexões antes de terminar o fio.

Eu recomendo entender o tópico, mas este artigo é uma boa fonte de informação.: http://www.ibm.com/developerworks/java/library/j-jtp05236/
 1
Author: TheIT, 2013-12-17 02:38:10
Eu diria que, em alguns casos, não há problema em não fazer nada. Provavelmente não algo que você deve estar fazendo por padrão, mas no caso de não deve haver nenhuma maneira para a interrupção acontecer, eu não tenho certeza do que mais fazer (provavelmente erro de registro, mas isso não afeta o fluxo do programa).

Um caso seria no caso de ter uma fila de Tarefas (bloqueio). No caso de ter um tópico do daemon a lidar com estas tarefas e de não interromper o tópico por si próprio (tanto quanto sei, o jvm não interrompe o daemon threads on jvm shutdown), I see no way for the interrupt to happen, and therefore it could be just ignored. (Eu sei que um fio de daemon pode ser morto pela jvm a qualquer momento e, portanto, são inadequados em alguns casos).

Editar: Outro caso pode ser guardado blocos, pelo menos com base no tutorial do Oracle em: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

 0
Author: Bjarne Boström, 2015-02-25 14:11:42