Java中的线程中断

1.概述
线程中断是一种机制,用于向线程发出信号,告知它必须在方便时停止执行。但是,是否检查中断状态并停止则取决于正在运行的任务。
2.使用Thread.interrupt中断
首先,我们将看到如何中断线程。 当我们在Thread实例上调用 interrupt时,它将设置线程的中断状态,以便代码的其他部分可以检查并对其执行操作。


public class TestInterrupt {
    public static void main(String[] args) {
        TestInterrupt testInterrupt=new TestInterrupt();
        testInterrupt.interruptThread();
    }
    public void interruptThread(){
        final Runnable task = () -> {
            int i = 0;
            while (i < Integer.MAX_VALUE) {
                i++;
            }
        };
        final Thread thread = new Thread(task);
        thread.start();

        System.out.println("Is thread interrupted: " + thread.isInterrupted());
        thread.interrupt();
        System.out.println("Is thread interrupted: " + thread.isInterrupted());
    }
}

在此示例中,我们首先创建一个Runnable任务。然后,我们 使用此任务启动一个线程。最后,我们在中断线程之前和之后观察中断状态。
运行样本打印:

Is thread interrupted: false
Is thread interrupted: true

如预期的那样,线程的中断标志在中断调用后变为true。
通常,有两个方面对中断感兴趣:执行任务的代码和拥有线程的代码。此外,它们可以根据中断请求单独执行操作。前面的示例包含任务和线程所有者。我们的代码是所有者,因为它创建了线程。处理中断是所有者的责任。例如,它可以终止线程或执行任何其他操作。由于我们不知道确切的影响,因此 只有所有者必须中断线程。

例如,在使用线程池时,任务不拥有工作线程,它们只是从基础池实现中借用它们。因此,当我们向线程池提交任务时,任务可以响应中断并可能取消其操作。但是它一定不能中断调用Thread.interrupt的工作线程。所述 的ExecutorService实现封装中断机制,并提供执行shutdownNow方法。这种方法使我们能够在线程池的监视下中断工作线程。

3.检查中断状态
在前面的示例中,我们使用Thread.isInterrupted 检查线程是否被中断。 当呼叫者执行此检查时,不会清除中断标志。换句话说,当多次调用时, isInterrupted返回相同的布尔值:

new Thread(() -> {
    Thread.currentThread().interrupt();
    System.out.println("Is thread interrupted: " + Thread.currentThread().isInterrupted());
    System.out.println("Is thread interrupted: " + Thread.currentThread().isInterrupted());
}).start();

在这里,我们首先中断当前线程。然后连续的isInterrupted调用都返回true:

Is thread interrupted: true
Is thread interrupted: true

该线程类还提供了一个静态的变体: Thread.interrupted。它检查当前线程的中断状态。 另外,它清除中断标志:

new Thread(() -> {
    Thread.currentThread().interrupt();
    System.out.println("Is thread interrupted: " + Thread.interrupted());
    System.out.println("Is thread interrupted: " + Thread.interrupted());
}).start();

输出显示此行为:

Is thread interrupted: true
Is thread interrupted: false

4.响应中断
接下来,我们将研究如何响应线程中断。如前所述,一个中断可以有多个接收者:任务和线程。

对于这些任务,我们必须使用它来取消正在运行的操作并在可能的情况下立即退出。这也是大多数Java类库采用的方法。

对于线程,如果代码不拥有线程(例如,在使用线程池时)或不负责应用中断策略,则必须保留中断请求。为此,我们必须抛出 InterruptedException或再次设置状态。

4.1。清除并抛出InterruptedException
作为第一种选择,我们将考虑在interrupt 上引发InterruptedException 。如果任务支持取消,则必须停止执行。取消之后,我们抛出一个 InterruptedException,以使堆栈上较高的代码处理该中断。

看一下示例:

public void handleAndThrowException() throws InterruptedException {
    final ExecutorService executorService = Executors.newSingleThreadExecutor();

    final Callable<Void> task = () -> {
        while (true) {
            if (Thread.interrupted()) {
                System.out.println("Interrupted, cleaning up and then throwing exception.");
                throw new InterruptedException();
            }

            // Do work.
        }
    };

    final Future<?> future = executorService.submit(task);

    TimeUnit.SECONDS.sleep(1); // Wait for some time

    final boolean cancel = future.cancel(true);
    System.out.println("Is cancelled?: " + cancel);

    executorService.shutdown();
}

在这里,我们使用线程池来执行任务。在Callable任务中,我们有一个while循环执行一些工作。请注意,我们的任务依赖于线程中断来取消。当它检测到中断时,它将清除并引发 InterruptedException。这样,我们就会有礼貌地表现并保持中断状态,以便池有机会对其执行操作。注意,我们不是直接调用 Thread.interrupt 。相反,我们正在请求一个调用Future.cancel的中断。

4.2。再次清除并中断
在Runnable任务中,我们不能抛出InterruptedException。否则我们可能不想抛出一个检查异常。在这些情况下, 如果清除,我们必须再次设置中断状态。

while (true) {
    if (Thread.interrupted()) {
        System.out.println("Interrupted, cleaning up and then throwing exception.");
        Thread.currentThread().interrupt();
        return "Canceled";
    }
    // Do work.
}

与前面的示例相似,该任务对中断做出响应,并尽快停止。而且,它保持呼叫者代码的中断状态。

4.3。响应InterruptedException
如果我们的代码是调用者并捕获了InterruptedException,则我们具有与前面相同的选项。我们可以重新抛出异常,也可以设置调用中断方法的中断状态 :

try {
    TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
    System.out.println("Interrupted, cleaning up and then setting the interrupt status.");
    Thread.currentThread().interrupt();
    return "Canceled";
}

return "Ok";

在这里,我们选择第二种方法并再次设置状态。

4.4。检查不清除
或者,我们可以使用 isInterrupted 检查状态。由于它不会清除状态,因此我们不需要抛出 InterruptedException或再次设置状态。

while (true) {
    if (Thread.currentThread().isInterrupted()) {
        System.out.println("Interrupted, cleaning up and then throwing exception.");
        return "Canceled";
    }

    // Do work.
}

4.5吞下中断请求
最后,如果代码对线程应用了中断策略,则可以清除中断状态。这意味着代码不在线程池上运行,而是管理自己的线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值