拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 如何在Java中处理InterruptedException

如何在Java中处理InterruptedException

白鹭 - 2021-11-21 2181 0 2

1.简介

在本教程中,我们将探讨Java的InterruptedException 。首先,我们将通过插图快速介绍线程的生命周期。接下来,我们将看到在多线程应用程序中进行工作可能如何导致InterruptedException 。最后,我们将看到如何处理此异常。

2.多线程基础

在讨论中断之前,让我们回顾一下多线程。多线程是同时执行两个或多个线程的过程。 main()方法相关联的单个线程(称为主线程)开始。然后,该主线程可以启动其他线程。

线程是轻量级的,这意味着它们在相同的内存空间中运行。因此,他们可以轻松地相互交流。让我们看一下线程的生命周期:

how-to-handle-interruptedexception-in-java.jpg

一旦我们创建了一个新线程,它就处于NEW状态。它将保持这种状态,直到程序使用start()方法启动线程为止。


在线程上调用start()方法会将其置于RUNNABLE状态。处于此状态的线程正在运行或准备运行。


当线程正在等待监视器锁定并尝试访问被某个其他线程锁定的代码时,它将进入BLOCKED状态。


可以通过各种事件(例如,调用wait()方法)将线程置于WAITING状态。在这种状态下,一个线程正在等待来自另一个线程的信号。


当线程完成执行或异常终止时,它将以TERMINATED状态结束。线程可以被中断,并且当线程被中断时,它将抛出InterruptedException 。


在下一节中,我们将InterruptedException并学习如何对其进行响应

3.什么是InterruptedException ?

当线程在等待,休眠或以其他方式占用时被中断时,将引发InterruptedException换句话说,某些代码在我们的线程上interrupt()这是一个已检查的异常,Java中的许多阻止操作都可以抛出该异常。

3.1 中断

断系统的目的是提供一个定义明确的框架,以允许线程中断其他线程中的任务(可能是耗时的任务)。考虑中断的一种好方法是它实际上并不中断正在运行的线程,它只是请求线程在下一个方便的时机中断自己。

3.2 阻塞和可中断方法

线程可能由于以下几个原因而阻塞:等待从Thread.sleep (),唤醒,等待获取锁,等待I / O完成或等待另一个线程中的计算结果, 其中。


InterruptedException ,以便可以对其进行处理并执行纠正措施。 Java中有几种方法会抛出InterruptedException 。这些包括Thread.sleep() , Thread.join() , Object类wait() ()方法以及BlockingQueue put()和take()方法,仅举几例。

3.3 线程中的中断方法

让我们快速看一下Thread类中用于处理中断的一些关键方法:

public void interrupt() { ... } public boolean isInterrupted() { ... } public static boolean interrupted() { ... }

Thread提供了interrupt()方法,并查询线程是否已被中断,我们可以使用isInterrupted()方法。有时,我们可能希望测试当前线程是否已被中断,如果已中断,则立即抛出此异常。在这里,我们可以使用interrupted()方法:

if (Thread.interrupted()) { throw new InterruptedException();

 }

3.4 中断状态标志

断机制使用称为中断状态的标志来实现。每个线程都有一个代表其中断状态boolean调用Thread.interrupt()设置此标志。当线程通过调用static方法Thread.interrupted()检查中断时,将清除中断状态。


要响应中断请求,我们必须处理InterruptedException.我们将在下一部分中看到如何做到这一点。

4.如何处理InterruptedException

要的是要注意线程调度是依赖于JVM的。这是自然的,因为JVM是虚拟机,并且需要本机操作系统资源来支持多线程。因此,我们不能保证线程永远不会中断。


中断表明线程应该停止正在执行的操作并执行其他操作。更具体地讲,如果我们编写将通过执行一些代码Executor或者其他某个线程管理机制,我们需要确保我们的代码响应及时中断。否则,我们的应用程序可能会导致死锁。


InterruptedException实用策略很少。让我们看看它们。

4.1 传播InterruptedException

我们可以允许InterruptedException向上传播到调用堆栈,例如,通过throws子句并让调用者确定如何处理中断。这可能涉及我们不捕获异常或捕获并重新抛出异常。让我们尝试通过一个示例来实现:

public static void propagateException() throws InterruptedException {

 Thread.sleep(1000);

 Thread.currentThread().interrupt(); if (Thread.interrupted()) { throw new InterruptedException();

 }

 }

在这里,我们正在检查线程是否被中断,如果是,则抛出InterruptedException 。现在,让我们调用propagateException()方法:

public static void main(String... args) throws InterruptedException {

 propagateException();

 }

当我们尝试运行这段代码时,我们将收到一个带有堆栈跟踪InterruptedException

Exception in thread "main" java.lang.InterruptedException

 at org.1ju.concurrent.interrupt.InterruptExample.propagateException(InterruptExample.java:16)

 at org.1ju.concurrent.interrupt.InterruptExample.main(InterruptExample.java:7)

尽管这是响应异常的最明智的方法,但有时我们无法抛出异常-例如,当我们的代码是Runnable的一部分时。在这种情况下,我们必须抓住它并恢复其状态。我们将在下一节中介绍如何处理这种情况。

4.2 恢复中断

在某些情况下,我们无法传播InterruptedException.例如,假设我们的任务是由Runnable定义的,或者重写了一个不会抛出任何已检查异常的方法。在这种情况下,我们可以保留中断。执行此操作的标准方法是恢复中断状态。

我们可以interrupt()方法(它将标志设置回true ),以便调用堆栈上方的代码可以看到已发出中断。例如,让我们中断一个线程并尝试访问其中断状态:

public class InterruptExample extends Thread { public static Boolean restoreTheState() {

 InterruptExample thread1 = new InterruptExample();

 thread1.start();

 thread1.interrupt(); return thread1.isInterrupted();

 }

 }

这是处理该中断并恢复中断状态run()

public void run() { try {

 Thread.sleep(1000);

 } catch (InterruptedException e) {

 Thread.currentThread().interrupt(); //set the flag back to true } }

后,让我们测试一下状态:

assertTrue(InterruptExample.restoreTheState());

尽管Java异常涵盖了所有特殊情况和条件,但是我们可能希望抛出特定于代码和业务逻辑的特定自定义异常。在这里,我们可以创建我们的自定义异常来处理中断。我们将在下一部分中看到它。

4.3 自定义异常处理

定制异常提供了添加标准Java异常不包含的属性和方法的灵活性。因此,根据情况以自定义方式处理中断是完全有效的。


我们可以完成其他工作,以允许应用程序正常处理中断请求。例如,当一个线程正在休眠或等待I / O操作,并且接收到中断时,我们可以在终止线程之前关闭任何资源。


让我们创建一个称为CustomInterruptedException的自定义检查异常

public class CustomInterruptedException extends Exception {

 CustomInterruptedException(String message) { super(message);

 }

 }

当线程被中断时,我们可以抛出CustomInterruptedException :

public static void throwCustomException() throws Exception {

 Thread.sleep(1000);

 Thread.currentThread().interrupt(); if (Thread.interrupted()) { throw new CustomInterruptedException("This thread was interrupted");

 }

 }

我们还看看如何检查异常是否与正确的消息一起拋出:

@Test

 public void whenThrowCustomException_thenContainsExpectedMessage() {

 Exception exception = assertThrows(CustomInterruptedException.class, () -> InterruptExample.throwCustomException());

 String expectedMessage = "This thread was interrupted";

 String actualMessage = exception.getMessage();



 assertTrue(actualMessage.contains(expectedMessage));

 }

同样,我们可以处理异常并恢复中断状态

public static Boolean handleWithCustomException() throws CustomInterruptedException{ try {

 Thread.sleep(1000);

 Thread.currentThread().interrupt();

 } catch (InterruptedException e) {

 Thread.currentThread().interrupt(); throw new CustomInterruptedException("This thread was interrupted...");

 } return Thread.currentThread().isInterrupted();

 }

我们可以通过检查中断状态以确保其返回true来测试代码:

assertTrue(InterruptExample.handleWithCustomException());

5.结论

在本教程中,我们看到了处理InterruptedException不同方法。如果我们正确处理它,我们可以平衡应用程序的响应能力和健壮性。


标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *