Отправка сигнала выключения другому потоку в Java

У меня есть приложение, которое многократно запускает что-то в цикле while в отдельном потоке, пока пользователь не активирует сигнал выключения. Я могу отправить сигнал из основного потока в рабочий поток, установив (изменчивое) логическое поле в рабочем потоке, но есть ли другой способ выключить / прервать поток, например с помощью какой-нибудь утилиты из java.util.concurrent?

Я попытался вызвать метод shutdown () или shutdownNow () ExecutorService, но им не удалось остановить рабочий поток. Также вызывается shutdown () и используется !Thread.currentThread().isInterrupted() в условии while, как рекомендуется здесь не может разорвать цикл. Единственный другой способ, который я мог найти, - это использовать CountDownLatch, но здесь мне пришлось бы использовать CountDownLatch.getCount() != 0 в условии для цикла while, но в документации javadoc этого метода говорится

Этот метод обычно используется для отладки и тестирования.

что делает сомнительный подход ИМО. Ниже мой пример кода

class Worker implements Runnable {
    //private volatile boolean shutdown = false; --> alternative to countdownlatch 
    @Override
    public void run() {

        while (countDownLatch.getCount() != 0) {
            //do some work    
        }
    }
}

public class App {
    public static void main(String[] args) {

    System.out.println("Press enter to stop");

    CountDownLatch countDownLatch = new CountDownLatch(1);

    ExecutorService es = Executors.newFixedThreadPool(1);
    es.execute(new Worker(countDownLatch));

    Scanner scanner = new Scanner(System.in);
    scanner.nextLine();

    System.out.println("Shut down signal received");

    countDownLatch.countDown();  //an alternative would be to set a boolean variable in worker

    es.shutdownNow();

}
}

Есть ли другой чистый способ сделать это?


person senseiwu    schedule 09.12.2013    source источник


Ответы (3)


Есть ли другой чистый способ сделать это? Нет. Используйте логическое значение (volatile).

Я уверен, что Thread.stop () будет работать, но нет возможности очистить его должным образом. Использование interrupted () / isInterrupted () будет работать, но это немного сложнее, чем логическое. Кроме того, бывают случаи, когда вы не хотите выходить из цикла только потому, что он был прерван. У меня есть код в нескольких местах, где я восстанавливаюсь после InterruptedException (или чего-то подобного), затем проверяю мое логическое значение (или что-то еще) и, в зависимости от его значения, продолжаю или нет.

Логическое значение хорошо сочетается с другими. Я упомянул прерывание. Когда-нибудь у вас может быть 20 разных причин для остановки цикла в любом из 10 (или более) мест. Это логическое значение подойдет прямо; вы можете легко написать код, чтобы ваш поток всегда останавливался, когда логическое значение истинно, или никогда, когда оно ложно, или что-то еще, что вам нужно сделать.

person RalphChapin    schedule 09.12.2013

Вы должны проверить Thread.interrupted () в своем цикле, чтобы закрыть его чем-либо, кроме System.exit (). Затем вы можете использовать thread.interrupt (), который в любом случае использует ExecutorService.shutdown (). Если это не работает, покажите нам свой код для проверки isInterrupted (), чтобы мы могли это исправить. Thread.stop () существует, но по уважительной причине устарел и не должен использоваться.

person Vitruvie    schedule 09.12.2013
comment
Я пробовал while (!Thread.currentThread().isInterrupted()) в условии цикла while для рабочего, и основной поток, вызывающий ExecutorService.shutdown (), а также shutdownNow () безуспешно. Мне интересно, гарантированно ли они вообще будут работать во всех случаях - person senseiwu; 09.12.2013
comment
@zencv Отредактировано для более прямого вызова функции. Вы пробовали просто использовать Thread t = new Thread (worker); ... t.interrupt () ;? - person Vitruvie; 09.12.2013

Вы можете получить [ExecutorService] [http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html] из [Executors] [http://docs.oracle.com/ javase / 7 / docs / api / java / util / concurrent / Executors.html]

Имея ссылку на ExecutorsService в основном потоке, вы можете выключить ThreadPool при получении сигнала.

person Vasanth    schedule 09.12.2013