【问题标题】:interrupting a thread after fixed time, does it have to throw InterruptedException?在固定时间后中断线程,是否必须抛出 InterruptedException?
【发布时间】:2012-04-19 08:53:24
【问题描述】:

我想在固定时间后中断一个线程。其他人问了同样的问题,票数最高的答案 (https://stackoverflow.com/a/2275596/1310503) 给出了下面的解决方案,我稍微缩短了。

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() 执行长时间运行的任务即可。

但是如果你用for (int i = 0; i &lt; 5E8; i++) {} 替换Thread.sleep(4000); 那么它不会编译,因为空循环不会抛出一个InterruptedException。为了使线程可中断,它需要抛出一个 InterruptedException。

有什么方法可以使上述代码与一般长时间运行的任务而不是sleep() 一起工作?

【问题讨论】:

    标签: java concurrency timeout


    【解决方案1】:

    如果您希望您的操作是可中断的(即应该可以在它完成之前中断它),您需要使用其他可中断操作(Thread.sleep、InputStream.read、read for more info)或手动检查线程中断使用 Thread.isInterrupted 在您的循环条件下的状态。

    【讨论】:

    • 我认为你是对的。我希望能够随时中断动作/任务,并且无需在动作/任务中编写特殊代码来检查它是否被中断,但我想这可能是不可能的。
    【解决方案2】:

    可以查看线程的中断状态,例如:

    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;
        }
    }
    

    【讨论】:

    • 但我想做的是随时中断一般任务,无论它在做什么。我不想在 Task 中插入特殊代码来检查它是否被中断,我不希望它只在每次迭代中的一个点可中断——例如,一个特定的迭代可能需要很长时间.
    • 这不是 Java 处理中断的方式——中断是一个协作过程,中断代码代码建议线程应该中断,但是每个被中断的线程都可以按照自己的意愿实现该请求,包括通过执行什么都没有并继续正常执行(显然不推荐)。有一个Thread.stop() 方法(参见here),但它已被弃用,您不应使用它。
    • 换句话说,在Java中,如果你想让一段代码是可中断的,你需要对它进行编码以感知中断并处理它们。
    • 谢谢,这一切都说得通
    • 如果其中一个答案帮助您解决了问题,您应该accept it 将问题标记为已关闭。
    【解决方案3】:

    你误会了。

    "...要使线程可中断,它需要抛出 InterruptedException" 根本不正确。那个 catch 块的存在只是因为Thread.sleep() 方法抛出了InterruptedException。如果你没有使用 sleep(或任何其他可以抛出 InterruptedException 的代码),那么你不需要 catch 块。

    【讨论】:

    • 如果你这样做,程序就不能工作——线程永远不会被中断。我认为我写的是真的。
    • 我知道我写的是真的 :-) 我怀疑你不能中断线程的原因是因为你让 CPU 忙于旋转,并且它需要在InterruptedException 被抛出之前进行某种系统调用。
    • 我不明白您所说的“在抛出 InterruptedException 之前”是什么意思。我们正在讨论一些不会抛出InterruptedException 的代码,不是吗?如果你写的是真的,如果你能给出一些代码,我将非常感激(a)可以用作Task.call()的主体,(b)不涉及InterruptedException,并且(c)是正确的被Test.main()打断了?
    • 它必然会涉及InterruptedException。但它不必重新抛出它或将其声明为已抛出或类似的东西。例如,如果您要将一些输出写入循环中的文件,而不是简单地进行忙转,那么您可能会发现可以更好地中断它。当您中断一个线程时,它不会生效,直到您进行系统调用或从系统调用返回,或者您在某些系统调用(读取、睡眠等)中被阻塞。您不能中断纯粹消耗 CPU 的线程你的忙自旋循环正在做。
    【解决方案4】:

    如果您替换 sleep,任何代码都不会抛出 InterruptedException。 您应该删除 InterruptedException 的 try-catch:

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

    【讨论】:

    • 如果你这样做,程序就不能工作——线程永远不会停止。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    相关资源
    最近更新 更多