2015-08-28 2 views
1

В настоящее время я запускаю нить из службы, чтобы выполнить некоторые фоновые работы. Теперь существует вероятность того, что Thread сбой или я хочу, чтобы прерывал поток из Сервиса. Так как я должен:Остановка прерывания потока/потоков после сбоя?

  1. остановить тему добросовестной, (жесткую)
  2. исключения уловов и вызовите службу о ручке InterruptedException аварии
  3. если прерван во время сна()
  4. является Thread. isInterrupted - хороший способ определить, остановился ли поток?

То, что я сделал до сих пор является следующее:

@Override 
public void run() { 
    try { 
     while (!Thread.currentThread().isInterrupted()) { 
      doMyBackgroundWork(); 
      sleep(); 
     } 
    }catch(Exception e){ 
     ExceptionHandler.logAndSendException(e); 
     Thread.currentThread().interrupt(); 
     if(crashedListener != null){ 
      crashedListener.onThreadCrashed(); 
     } 
    } 
    LOG.i("Thread stops now."); 
} 

private void sleep() { 
    try { 
     sleep(frequency); 
    } catch (InterruptedException e) { 
     //what to do here? it can happen because I stopped it myself 
    } 
} 

Таким образом, в первом я бегу моя тема, пока она не будет прервана. Если возникло какое-либо исключение, я хочу начать новый Thread, поэтому my Service реализует интерфейс прослушивателя, и я вызываю его, как только вызывается Исключение. Я знаю, что ловить все не рекомендуется, , но мне нужно знать, останавливается ли Thread, без опроса Thread.isAlive() все время.

Кроме моих четырех вопросов выше:

  • мой код надежен и делает то, что мне нужно?
  • Можно ли вызвать прерывание на самой теме?

Спасибо!

+0

Возможно, это поможет вам, сделайте новую тему для проверки делает исключение брошено – RadijatoR

ответ

1

Вы фактически не прерываете свой собственный поток, потому что блок catch находится вне цикла while. Поэтому любое исключение немедленно прекратит выполнение.

Прерывание - это просто запрос (обычно из другого потока), чтобы прекратить делать то, что вы делаете. Поток может игнорировать его и продолжать делать то, что он делает. Обычно вам нужно выкинуть исключение в ответ на прерывание или остановить выполнение каким-либо другим способом, например, просто выйти из цикла (вам нужно это в комментарии //what to do here?). Так получилось, что некоторые библиотечные методы «реагируют на прерывание», что означает, что они будут генерировать исключение, если поток прерывается, например Thread.sleep(), который, скорее всего, будет иметься в вашем вызове sleep.

Я рекомендую выбирать Java Concurrency In Practice. Среди превосходного материала параллелизма есть глава о прерываниях, которая очень полезна.

EDIT: Я бы удалил код, в котором вы прерываете свою тему. Вам также потребуется перестроить InterruptedException как исключение во время выполнения, чтобы выйти из цикла выполнения. Обычно люди создадут новое исключение, которое расширяет RuntimeException, что-то вроде MyInterruptedException. Затем вы можете добавить его в блок catch вокруг вашего цикла, чтобы вы знали, когда поток был прерван, а выполнение завершилось неудачно.

В общем примере вы можете сделать что-то вроде этого:

public void run() { 
    try { 
     while (true) { 
      // check for interrupts in the loop, or somewhere in the work method 
      if (Thread.interrupted()) { 
       throw new MyInterruptedException("Important thread interrupted."); 
      } 
      doMyBackgroundWork(); 
      sleep(); 
     } 
    } 
    catch(Exception e){ 
     ExceptionHandler.logAndSendException(e); 
     if(crashedListener != null){ 
      crashedListener.onThreadCrashed(); 
     } 
    } 
    catch(MyInterruptedException i) { 
     LOG.i("Execution stopping because of interrupt."); 
    } 
} 

private void sleep() { 
    try { 
     sleep(frequency); 
    } catch (InterruptedException e) { 
     throw new MyInterrptedException(e); 
    } 
} 
+0

Спасибо! У меня также была проблема, что я не смог остановить свою нить (как вы сказали - я поймал InterruptedException * duh *) и закончил с 4-5 нитями одновременно. Теперь я попробую ваш пример. Дайте мне несколько секунд. – JacksOnF1re

+1

Поскольку вы упоминаете несколько потоков, я бы также рекомендовал использовать «ExecutorService» вместо того, чтобы пытаться управлять ими самостоятельно. Исполнитель может обрабатывать постоянный пул потоков, регенерировать их, когда они умирают и т. Д. – mvd

+0

Допустим, у меня есть Executer с размером пула 1. Если мне нужно остановить поток и запустить другой, выполнит ли executer нить? Имеются ли какие-либо временные недостатки? – JacksOnF1re

0

у нас есть хороший и эффективный метод, называемый stop() (Thread.stop(void):void), который устарел, но это работает, и это прекрасно.

Обратите внимание, что stop() бросает ThreadDeath на целевой поток, который не является исключением (и это может любой другой throwable тоже), но Error, так что ваш код не будет поймать любой сигнал об этом.

public void run() { 
    try { 
     while (<<using_a_volatile_bool_type_is_better>>) { 
      ... 
     } 
    }catch(Throwable t){/**/}/*use throwable instead of exception.*/} 
} 

Помимо дорогого друга stop() мы также pause() метод тоже, и это действительно делает паузу целевой поток.

Не только одно решение, но и очень важно, чтобы поток выполнялся и выполнялся аварийный режим (или сам) сразу после любого сбоя, вы можете запускать его как отдельное приложение/процесс, а также получать статус выполнения (если любой), который гарантирует, что целевая нить/приложение не зависает (заблокировано, ...)