ExecutorService - уничтожение потока после определенного срока - PullRequest
0 голосов
/ 25 октября 2019

Я создал ExecutorService и отправил работу. Работа может занять много времени. Так что я дал timeout как 2 секунды. Если выполнение занимает более 2 секунд, я хочу уничтожить этот поток.

public void threadTest() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        try {
            executor.submit(() -> {
                try {
                    String threadName = Thread.currentThread().getName();
                    Thread.sleep(7000);
                    System.out.println("process completed after 7 seconds");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).get(2, TimeUnit.SECONDS);
        }catch (Exception e){
        }
        executor.shutdown();

    }

    public static void main(String[] args) throws Exception {
        System.out.println("main start");
        ThreadBreaker tb = new ThreadBreaker();
        tb.threadTest();
        System.out.println("main end");
    }

output

main start
main end
process completed after 7 seconds

Функция threadTest вышла через 2 секунды, как я и ожидал. Но представленная работа продолжалась. Я хочу остановить отправленное задание, если оно не может быть выполнено в течение заданного времени ожидания.

Ответы [ 2 ]

0 голосов
/ 25 октября 2019

Когда вы используете ExecutorService, вы не можете убивать потоки самостоятельно. ThreadPool решает, когда убить Thread (обычно это может произойти, если Thread был прерван).

В вашем случае вы должны поймать TimeoutException и cancel Future. Если ваша «реальная» задача реагирует на прерывание (вызывая и обрабатывая InterruptedException правильно), она будет работать. В противном случае вам следует проверить состояние Thread.currentThread().isInterrupted() в цикле. Ваш пример кода будет выглядеть так:

public void threadTest() {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<?> submit = executor.submit(() -> {
        try {
            String threadName = Thread.currentThread().getName();
            Thread.sleep(7000);
            System.out.println("process completed after 7 seconds");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); //preserve interruption status. based on this ThreadPool's interruption Policy will decide what to do with the Thread
        }
    });

    try {
        submit.get(2, TimeUnit.SECONDS);
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace(); //handle this
    } catch (TimeoutException e) {
        submit.cancel(true); //cancel the task
    }
    executor.shutdown();

}

Также помните, что если вы выполняете задачу в ThreadPool и выполняете операции, которые могут быть с InterruptedException, в большинстве случаев вы должны сохранить статус прерывания.

0 голосов
/ 25 октября 2019

После того как вы отправили задачу executorService, у вас есть объект Future. И вы можете отменить выполнение с помощью вызова Future.cancel (true).

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

В примеревыше:

 Thread.sleep(7000); 

вызовет прерванное исключение, и вы не должны его ловить (или, если вы его поймали, повторно вызвать другое исключение)

...