在本教程中,我们将 通过一个例子来学习InterruptedException以及它何时被抛出。我们还将看到在多线程应用程序中工作时,我们如何在代码中处理InterruptedException。
1.Java中的InterruptedException
1.1.什么是中断?
在并发中,中断是一个信号,让Thread停止自己,并找出下一步该做什么。一般来说,它要求Thread优雅地终止自己。
当一个线程在等待、睡眠或其他情况下被占用时,另一个线程通过使用Thread类中的interrupt()方法来中断它,就会抛出InterruptedException。
在内部,中断机制是通过一个称为中断状态的内部标志来实现的。当一个线程调用interrupt()方法时,这个标志就会被设置,我们可以使用isInterrupted() 方法来检查这个标志的状态。在Thread类中还有一个方法。 Thread.interrupted()可以再次清除这个标志以响应其他中断请求。
请注意,Thread 类包含以下用于创建和检查中断的方法。
void interrupt():中断一个线程boolean isInterrupted():检查当前线程 是否被中断。 线程 的中断状态不受此方法的影响。boolean interrupted():检查当前线程 是否已被中断。该 线程 的中断状态被此方法清除。
1.2.Thread.interrupt()方法
interrupt()方法会中断它所调用的线程。
- 如果该线程在调用sleep()、wait()或join()方法时被阻塞,那么它的中断状态将被清除,并且会收到一个InterruptedException。
- 如果该线程在对一个*可中断通道的I/O操作中被阻塞,那么该通道将被关闭,该线程的中断状态将被设置,并且该线程将收到一个ClosedByInterruptException。
- 如果该线程在java.nio.channels.Selector中被阻塞,那么该线程的中断状态将被设置,并且它将立即从选择操作中返回。
- 如果前面的条件都不成立,那么这个线程的中断状态将被设置,我们可以使用
isInterrupted()或interrupted()方法来检查。
2.如何中断一个线程
一个线程 可以通过使用Thread 类的interrupt() 方法来中断另一个正在等待或睡眠的线程 。
在下面的例子中,TestThread每隔2秒就定期工作一次。它检查它是否被打断了。如果没有,它继续工作,完成处理并返回。如果它在中间被另一个线程打断,它可以通过向调用者线程抛出InterruptedException来优雅地终止工作。
public class TestThread extends Thread {
public void run() {
try{
while(true) {
// Check if it is interrupted, if so then throw InterruptedException
if(Thread.interrupted()) {
throw new InterruptedException();
}
// else continue working
else {
System.out.println("Continue working");
}
Thread.sleep(2000L);
}
} catch (InterruptedException e) {
// Handling InterruptedException and Graceful shutdown of the Thread
System.out.println("Graceful shutdown");
}
}
}
另一个启动它的线程(例如:主线程)有时会决定TestThread执行的任务不再需要了,所以它中断了它。
// TestThread Instantiation
TestThread t1 = new TestThread();
// Starting TestThread
t1.start();
// main Thread enters into sleeping state
Thread.sleep(5000);
// main Thread decided that TestThread is no longer needed, so interrupting it
t1.interrupt();
当我们执行这个程序时,我们将得到以下输出。
Continue working
Continue working
Continue working
Graceful Termination
3.处理InterruptedException
当在一个多线程的应用程序中工作时,优雅地处理InterruptedException是很重要的,线程应该及时响应中断,以避免应用程序进入死锁 状态。
- 由于InterruptedException 是一个*被检查的异常,所以我们必须使用try-catch或throws* 关键字来处理它。
- 我们可以通过使用throws 关键字将其在堆栈中向上传播到调用者方法。在这种情况下,调用者方法需要处理这个异常。
- 在有些情况下,抛出异常是不可能的,比如Runnable接口的
run()方法,它不允许抛出异常,所以对于这些情况,我们可以使用try-catch块,在 调用Thread本身 明确地处理这个异常,而不是抛出它。
让我们考虑第一种情况,当一个被中断的线程 抛出InterruptedException ,并要求调用者方法处理它,而不是自己处理它。
// method throwing InterruptedException so that it is propagated to the caller method
public static void throwInterruptedException() throws InterruptedException
{
// Thread enters into sleeping state
Thread.sleep(1000);
// Thread interrupting itself
Thread.currentThread().interrupt();
// check if the Thread is interrupted
if (Thread.interrupted()) {
// Throwing InterruptedException
throw new InterruptedException();
}
}
// main method
public static void main(String[] args)
{
try{
// calling a method that throws InterruptedException
throwInterruptedException();
} catch(InterruptedException e){
System.out.println("Thread interrupted by throwing the exception")
}
}
现在让我们考虑这样的情况:一个被中断的线程 自己用try-catch块来处理InterruptedException,而不是用throws关键字将其传播给调用者方法。
// method handling InterruptedException using try-catch block
public void run()
{
try{
// Thread enters into sleeping state
Thread.sleep(1000);
// Thread interrupting itself
Thread.currentThread().interrupt();
} catch(InterruptedException e){
System.out.println("Thread interrupted and handling exception by itself")
}
}
// main method
public static void main(String[] args)
{
// Creating new Thread
Thread thread = new Thread();
// Starting a Thread
thread.start();
}
我们也可以通过扩展Exception 类来创建用户定义的异常(我们自己定制的InterruptedException),并在需要时从代码中抛出我们定制的异常。
// Creating Custom InterruptedException
public class CustomInterruptedException extends Exception
{
CustomInterruptedException(String message) {
super(message);
}
}
// method throwing our CustomInterruptedException
public void throwCustomException() throws CustomInterruptedException
{
// Thread enters into sleeping state
Thread.sleep(1000);
// Thread interrupting itself
Thread.currentThread().interrupt();
// check if the Thread is interrupted
if (Thread.interrupted())
{
// Throwing CustomInterruptedException
throw new CustomInterruptedException("Thread interrupted by throwing custom exception");
}
}
3.总结
这篇文章让我们了解了InterruptedException,它的构造函数,方法和产生的原因。我们也看到了在我们的代码中处理中断异常的各种方法。