Невозможно отменить запущенную задачу с помощью SingleThreadExecutor

#java #threadpool

#java #threadpool

Вопрос:

У меня есть класс, реализующий Runnable:

 public class Abc implements Runnable{
    public synchronized void run(){
        while(!(Thread.currentThread().isInterrupted() || someCondition())){
           doSomething();
           try{
               this.wait(SOME_TIME);
           } catch(InterruptedException ex){
            logger.error("Ex",ex);
            Thread.currentThread.interrupt();
               }
}}}
  

После отправки ее в threadpool я хотел бы отменить ее с помощью прерывания.

 futureTask.cancel(true);
  

Но сегодня мой Runnable объект перестал получать прерывание.
Я вышел из состояния прерывания: false. InterruptedException не генерируется. Есть предложения, что не так?

Ответ №1:

Я предполагаю, что прерывание было использовано doSomething или doSomething было связано (не возвращается)

Использование wait() в подобном цикле подсказывает мне, что у вас есть поток управления, который лучше подходит для использования библиотек параллелизма. Можете ли вы дать более подробную информацию о том, чего вы ждете?

Кстати, если вы переместите try / cath за пределы цикла, это упростит его.

Комментарии:

1. Я выполняю некоторые вычисления перед обновлением индикатора выполнения (с помощью SwingUtilities.invokeLater ). Затем я жду 400 мс и делаю это снова, пока не установлю 100% или пользователь не нажмет «Отмена». Перемещение try catch наружу, пока не помогло, doSomething() само по себе не улавливает никаких исключений.

2. После вызова interrupt () можете ли вы вызвать getStackTrace() в потоке, чтобы посмотреть, что он делает?

Ответ №2:

Сначала ваш фрагмент даже не компилируется: вам не хватает фигурных скобок, Thread.currentThread — это метод, а не переменная экземпляра. Затем вы вызываете Thread.interrupted() в своем методе doSomething? Если да: это очищает прерванное состояние потока, так что ожидание не будет прервано, а currentThread().isInterrupted() вернет false .

Вам также не нужно перепроверять состояние прерывания в предложении while или повторно прерывать поток, как только он был прерван. Это выглядит приятнее (и улавливает исключение, которое может выдать ваш doSomething):

   public synchronized void run() {
    try {
      while (!someCondition()) {
        doSomething();
        wait(SOME_TIME);
      }
    } catch (InterruptedException ie) {
      logger.error(ie);
    } catch (Exception e) {
      logger.error(e);
    }
  }
  

@Peter: перенос try / catch пока, безусловно, хорошее предложение!

Комментарии:

1. Я писал, когда был голоден … извините. Я отредактировал свой пост. Нет, я не вызываю Thread.interrupted() .

2. выведите сообщение в конце метода run, он все еще выполняется, когда вы пытаетесь прервать его?

3. Это очень странно, потому что похоже, что while не возвращается (не отображает logger после выхода из while цикла, но все еще отображает logger в someCondition ), хотя недавно отправленные задачи выполняются.

Ответ №3:

Решаемая

На самом деле это было очень сложное условие гонки. Я запускал задачу из потока gui и отменял ее из потока network reader. Я не могу объяснить, почему log4j не отображал регистраторы, но лучшее управление потоками решило мою проблему. Ваши ответы помогли мне найти идею для ее решения, спасибо.

Когда что-то работало вчера, но не сегодня — вероятно, это состояние гонки или взаимоблокировка. 🙂