Прерывая поток после установленного времени, нужно ли его бросать InterruptedException?

Я хочу прервать поток через определенное количество времени. Кто-то другой задал один и тот же вопрос, и верхний проголосовавший ответ (qaru.site/info/21288/...) дал нижеприведенное решение, которое я немного сократил.

import java.util.Arrays;
import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.invokeAll(Arrays.asList(new Task()), 2, TimeUnit.SECONDS);
        executor.shutdown();
    }
}

class Task implements Callable<String> {
    public String call() throws Exception {
        try {
            System.out.println("Started..");
            Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
            System.out.println("Finished!");
        } catch (InterruptedException e) {
            System.out.println("Terminated!");
        }
        return null;
    }
}

Они добавили:

sleep() не требуется. Он используется только для целей SSCCE/демонстрации. Просто выполняйте свою длинную работу прямо там вместо sleep().

Но если вы замените Thread.sleep(4000); на for (int i = 0; i < 5E8; i++) {}, то он не скомпилируется, потому что пустой цикл не вызывает прерывание Exception. И для того, чтобы поток был прерываемым, ему нужно вывести InterruptedException.

Есть ли способ сделать вышеуказанный код работать с общей долговременной задачей вместо sleep()?

Ответ 1

Если вы хотите, чтобы действие было прерываемым (т.е. должно быть возможно прервать его до его завершения), вам нужно либо использовать другое прерывистое действие (Thread.sleep, InputStream.read, прочитать для дополнительной информации) или вручную проверить статус прерывания потока в вашем состоянии цикла с помощью Thread.isInterrupted.

Ответ 2

Вы неправильно поняли.

"... для того, чтобы поток был прерываемым, ему нужно было перебросить InterruptedException", это просто неверно. Этот блок catch существует только потому, что метод Thread.sleep() вызывает InterruptedException. Если вы не используете сон (или любой другой код, который может бросать InterruptedException), вам не нужен блок catch.

Ответ 3

Вы можете проверить прерванный статус потока, например:

public static void main(String[] args) throws Exception {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.invokeAll(Arrays.asList(new Task()), 2, TimeUnit.SECONDS);
    executor.shutdown();
}

static class Task implements Callable<String> {

    public String call() throws Exception {
        System.out.println("Started..");
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("Interrupted!");
                return null;
            }
        }
        System.out.println("Finished!");
        return null;
    }
}

Ответ 4

Ни один из кода не будет бросать InterruptedException, если вы замените sleep. Вы должны удалить try-catch для InterruptedException:

public String call() {
    System.out.println("Started..");
    for (int i = 0; i < 5E8; i++) {}
    System.out.println("Finished!");
    return null;
}