2016-01-07 2 views
2

У меня есть несколько вопросов о ExecutorService и о завершении работы. Мой случай использования: Я использую ExecutorService нереститься фиксированное число потоков, чей пробег способ выглядеть следующим образом:ExecutorService ждут сигнала завершения работы в экземпляре Runnable

while (true) { 
    try { 
     this.currentThreadRunning = true; 
     processMessage(); 
    } 
    catch (Throwable e) { 
     // Keeping the thread alive despite exceptions. 
    } 
} 

Эти потоки выполняются бесконечно, опрос для сообщений.

Что я пытаюсь сделать? Я обрабатываю очередь SQS для сообщений и обрабатываю их.

Очевидно, что в моем случае метод останова ExecutorService's не будет работать. Когда вызывается shutdownNow(), все мои потоки прерываются бесцеремонно. Я ненавижу это!

Есть ли способ вызвать awaitTermination и проверить в моем Runnable экземпляре (в блоке finally?), Если выключение было инициировано и активировано для текущего потока?

ОБНОВЛЕНИЕ: Я переработал свой код для выполнения опроса, а затем создавал потоки для их обработки. Таким образом, метод запуска экземпляра Runnable не должен быть бесконечным циклом. И awaiTermination приведет к определенному закрытию нитей. И, конечно же, я вызвал shutdownNow после awaitTermination.

+0

Чтобы создать бесконечное количество потоков, вам нужно бесконечное количество ядер и памяти процессора. У вас есть это? –

+0

Обычным использованием исполнителя будет создание новой задачи для каждого обрабатываемого сообщения. – SpaceTrucker

+0

@Sleiman - существует фиксированное количество потоков. Но они бегут бесконечно. Я обновлю вопрос, чтобы соответствующим образом отразить сценарий. – user657592

ответ

0

Я думаю, что вы делаете концептуально неправильно.

awaitTermination предназначен для того, чтобы подождать, пока все потоки закончатся естественным образом, а затем остановите исполнителя. При отправке Runnable он не должен иметь представления о контексте его выполнения, поэтому соединение вашего запуска с вашим исполнителем не является хорошей идеей ИМХО.

Возможно, вам стоит изучить класс Future и переместить туда Runnable. Затем вам придется применить метод cancel(boolean), который может вам пригодиться.

Что такое ваш прецедент?Возможно, если вы это объясните, сообщество может указать на более подходящую реализацию.

+0

Я получил аналогичную обратную связь. Но позвольте мне повторить: мне нужен механизм, где я могу проверить, был ли отправлен запрос на завершение из «ExecutorService» в методе Runnable. - Когда выключение сигнализируется «ExecutorService», не будет ли поток знать об этом? Я не хочу проверять, было ли «ExecutorService» сигнализировано о завершении работы, но если поток получил такой сигнал. Согласился, что это тонкая грань. Но ваши мысли и мнение помогут. – user657592

+0

Это взято из документации 'shutdownNow()' - Нет никаких гарантий, кроме лучших попыток прекратить обработку, активно выполняющую задачи. Например, типичные реализации будут отменены с помощью {@link Thread # interrupt}, поэтому любая задача, которая не отвечает на прерывания, может никогда не завершиться. Таким образом, обычно вы должны получать прерывание. Однако нет никакой гарантии, что это будет так. Если вы полагаетесь на это, вы связываете свою управляемую логику с конкретной реализацией исполнителя, и вам стоит подумать, стоит ли компромисс в вашем случае. –

0

Для бесконечно работает Runnables я полагаюсь на подхватить InterruptedException, который, как правило, быть выброшен из моего вызова shutdownNow() или иногда от вызова Future#cancel(true)

while(!Thread.interrupted()) { 
    try { 

    } catch(InterruptedException e) { 
     break; 
    } catch(Throwable e) { 
     // Keeping the thread alive despite exception 
    } 
} 
// Thread was interrupted via shutdownNow(), cleanup resources 

Если мне нужно различать возобновляемое прерывания и отключение прерывания, то Я разделяю AtomicBoolean doShutdown среди моих Runnables, который инициализируется false и устанавливается в true, если я хочу, чтобы InterruptedException прекратил нить.

+1

вы должны восстановить прерванный статус после перехвата InterruptedException, чтобы код вызова также мог обрабатывать прерывания. – SpaceTrucker

0

Вы должны проверить статус прерывания потока, в котором вы работаете (см. Руководство по прерываниям здесь: https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html). Ваш код должен быть:

while (!Thread.currentThread().isInterrupted()) { 
     try { 
      this.currentThreadRunning = true; 
      processMessage(); 
     } 
     catch (Throwable e) { 
      // Keeping the thread alive despite exceptions. 
     } 
} 

Однако обратите внимание, что вы должны правильно обрабатывать прерывания в коде вызывается из ваших работоспособных. Если есть что-нибудь вроде следующего:

try { 
    // do something 
} catch(InterruptedException e) { 
    // ignore 
} 

тогда это не сработает. Правильный способ обработки InterruptedException - позвонить по телефону Thread.currentThread().interrupt();.

+0

«awaitTermination» отправляет прерывание потокам? – user657592

+0

нет .. это не. если вы вызовете shutdownNow, тогда поток получит прерывание – awsome

0

Вы не должны звонить shutdownNow() Но вы должны только вызывать выключение и использовать awaitTermination, чтобы подождать некоторое время.

Так выключение будет что-то вроде этого

Объявить летучий переменную

private volatile stopThread = false; 

При останове вызове

this.stopThread = true; 
executor.shutdown(); 
executor.awaitTermination(.. 
executor.shutdownNow() // in case termination takes too long 

И в потоке вы проверить переменную stopThread. Вы не можете использовать isInterrupted здесь, потому что мы не прерываем поток. мы просто ждем нити, чтобы выйти на основе этого условия

if(stopThread){ 
// calling off all the operations and returning 
} 

Я написал статью о shuting вниз ExecutorService правильно http://programtalk.com/java/executorservice-not-shutting-down/ Я надеюсь, что это поможет.

Смежные вопросы