Как принудительно остановить бесконечный цикл Thread

Ниже приведен фрагмент кода

ExecutorService executor = Executors.newSingleThreadExecutor();

executor.submit(() -> {
    while (true) System.out.println("1");
});
executor.shutdown();
executor.shutdownNow();

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

Что вы подразумеваете под снаружи?

ernest_k 14.05.2019 09:46

Нет, не изменив задачу, вы не сможете ее остановить.

Andy Turner 14.05.2019 09:48

Если поток представляет собой цикл, вы можете инвертировать управление: в конце цикла заставьте поток спрашивать, следует ли ему переходить к следующей итерации. Вы можете сделать это через переменную, файл, базу данных и т.д.

Arnaud Denoyelle 14.05.2019 09:48

Все, что вы можете сделать с реальным кодом, — это «попытаться» остановить поток, выполняющий цикл. Если это основной поток, то вам нужно убить приложение.

AxelH 14.05.2019 10:12

Спасибо за ответ :)

Santonio 15.05.2019 10:46

в linux мы можем принудительно остановить процесс независимо от того, что это такое. поэтому мне интересно, есть ли в java механизм, подобный сигналу kill -9 в linux, чтобы принудительно остановить поток

Santonio 15.05.2019 10:50
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
136
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Есть несколько способов

  1. Добавьте дополнительное условие к условию цикла, например boolean shouldContinue, чтобы установка этого значения на false приводила к выходу из цикла в какой-то момент.
  2. Если вы можете написать свои собственные функции (у вас есть приложение), вы можете написать код, чтобы перечислить все потоки и заставить данный поток прекратить использование Thread#stop (небезопасно) или Thread#interrupt (безопаснее).
  3. Если у вас нет приложения — например, вы используете какое-то приложение — вы можете запустить его с помощью пользовательского javaagent, что позволит вам делать то же самое, что и в пункте 2.

Как 2, так и 3, с тщательной интеграцией, например, с сокетами, могут позволить вам сделать это в уже запущенном процессе извне, например. из командной строки

Только не забудьте использовать ключевое слово volatile в первом случае.

Paul Lemarchand 14.05.2019 09:58

"предлагать не может изменить саму задачу"

Andy Turner 14.05.2019 09:59

@AndyTurner 3-й вариант тогда.

Antoniossss 14.05.2019 10:10

Почему бы вам не использовать ScheduledExecutorService вместо обычного ExecutorService?

Вы можете захватить Будущее, то есть задачу, которая выполняется (или будет) выполняться, и отменять ее «извне» по своему усмотрению.

public class Example {
    private ScheduledFuture mThread;
    private final ScheduledExecutorService mExecutor = Executors.newScheduledThreadPool(1);

    public void executeForever() {
        mThread = mExecutor.schedule(() -> { while (true) System.out.println("1"); }, 0, TimeUnit.NANOSECONDS);
    }

    public void cancelThread() {
        mThread.cancel(true);
    }
}

Ваш ScheduledFuture также унаследует все методы интерфейса Future, такие как cancel, get, isCancelled и isDone.

Дополнительная информация о ScheduledFuture: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledFuture.html

Дополнительная информация о ScheduledExecutorService: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html

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

Не этот конкретный фрагмент, я в основном сделал базовую реализацию того, что делает ScheduledExecutorService, почему вы говорите, что это не сработает? Обновлено: я только что заметил, что логический флаг для метода отмены требуется, чтобы уведомить, следует ли его отменить, даже если он запущен.

Daniel Campos Olivares 14.05.2019 10:14
Ответ принят как подходящий

Пожалуйста, прочитайте javadoc для метода завершение работы (). Очень ясно сказано:

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.

Итак, что вам нужно сделать, это изменить отправленную задачу в коде, чтобы она реагировала на метод Thread.interrupt(). т.е. вам нужно изменить свою строку
while (true)
на
while (true && !Thread.currentTrhead().isInterrupted())
для более подробной информации прочитайте javadoc для Класс потока в конкретных методах interrupt(), interrupted() и isInterrupted()

Если вы раскрываете поток, в котором вас запускает исполнитель, вы можете прервать его. Для меня это печатает 1 только 4 раза, предполагая, что прерывание прошло успешно.

Помните, что это зависит от того факта, что Thread.sleep и System.out.println прерываемы. Если вы не проверяете Thread.isInterrupted (как они оба делают), вы все равно не сможете прервать поток.

ExecutorService executor = Executors.newSingleThreadExecutor();

private void test() throws InterruptedException {
    AtomicReference<Thread> thread = new AtomicReference<>();
    Future<Object> task = executor.submit(() -> {
        // Keep track of the thread.
        thread.set(Thread.currentThread());
        try {
            while (true) {
                Thread.sleep(1000);
                System.out.println("1");
            }
        } finally {
            System.out.println("Interrupted: " + Thread.currentThread().isInterrupted());
        }
    });
    Thread.sleep(5000);
    // Interrupt the thread.
    thread.get().interrupt();
    Thread.sleep(5000);
    System.out.println("Press <Enter> to shutdown");
    new Scanner(System.in).nextLine();
    executor.shutdown();
    System.out.println("Press <Enter> to shutdown NOW");
    new Scanner(System.in).nextLine();
    executor.shutdownNow();
}

Другие вопросы по теме