如何触发Thread.sleep抛出的InterruptedException?

简介: 其实说来也简单,就是Thread.sleep所在的线程被interrupt了就抛出InterruptedException,但由于历史遗留问题这个十分罕见的情况变成了所有开发者都需要处理的常情,从这个细节的设计可以看出Thread这个类的历史遗留相当严重,其实java早已无法完全兼容旧版本,删除废弃了很多API,但仍然无法改良这些关键部分的设计。

InterruptedException由Sun Microsystems公司的前任工程师Frank Yellin编写,发布于JDK1.0沿用至今,不过它并不是一个常见的Exception,只有在直接或间接调用如下方法的时候才会触发它

java.lang.Object java.lang.Thread
wait() join()
wait(long) join(long)
wait(long, int) join(long, int)
sleep(long)
sleep(long, int)

以上方法可都会throws出InterruptedException,但InterruptedException并不常见,例如Thread.sleep(long)就经常被用来休眠线程,却很少会遇到InterruptedException,那么究竟是在什么情况下才会触发它呢?请看这个例子:

// demo1
Thread.currentThread().interrupt();
try {
   
    Thread.sleep(200);
} catch (InterruptedException e) {
   
    e.printStackTrace();
}

Thread中interrupt()方法是个关键,它使线程陷入中断状态,在中断状态中调用sleep方法,立刻触发如下异常

java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    ...

这是正确的结果,因为上面的例子调用interrupt()中断了线程,然后又休眠线程,这是不合理的。


但是这又是有用的,正如sleep()的Javadoc中所说

@throws InterruptedException
if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

意思是说,如果当前线程被中断,则会抛出此异常,并且清除当前线程的中断状态

那么中断状态被清除掉之后,是否就可以使用sleep()呢?下面尝试一下在demo1的catch块中再次sleep

// demo2
Thread.currentThread().interrupt();
try {
    Thread.sleep(200);
} catch (InterruptedException e) {
    try {
        Thread.sleep(200);
        System.out.println("success");
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
}

此时demo2成功运行,没有进入第二个catch块,输出

success

果如文档所说,但我觉得这真的是一个神奇又有点搞笑的操作。

在单线程的情况下并不容易遇到,因为在线程interrupt后休眠线程不合情理,也很少有情况会interrupt当前的线程,但在多线程的情况下,确实不易感觉到

Thread foo = new Thread(() -> {
    try {
        Thread.sleep(200);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
foo.start();
foo.interrupt();

然后就能看到这个报错了:

java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    ...

线程foo启动后调用了interrupt(),此时foo尚未正式运行,因为启动线程需要一定的时间,而foo线程被interrupt后还在运行,执行sleep时就会遇到这个异常。问题的关键就在于只要休眠一个处于中断状态的线程,InterruptedException自然会随之而来。

总结

如果一个线程被interrupt,并在之后进行sleep()wait()join()这三种操作,那么InterruptedException就会被触发。如果你确保你的线程在自己的控制之中,不会莫名其妙的去interrupt(),就可以当这个异常不存在,这个是几乎不太可能遇到的异常。

说实话感觉这个异常真的意义有限,既不会因为外部因素导致异常,也没有什么利用价值,如果放到现在重新设计,最起码也是把这个异常设成RuntimeException吧,强制抛这种几乎没人在意的错,就没想过所有人在调用Thread.sleep()时都要多写这一大坨try-catch块吗?

如本文开头所说,这是JDK1.0留下来的历史遗留问题,这么不合理的异常设计遗留到现在,可以说Thread这整个类已经写了两千多行了,已经是一大坨了,很难改了。照理来说应该和java.util.Date一样直接开个新的类,可以保留原有的类,但后面关于线程的东西都重新设计,并且覆盖之前的类的功能,但JDK19新出的虚拟线程Thread.startVirtualThread()还要丢进这个破类,真是不思进取,下头。

本文写作于2018年11月14日发布于lyrieek的简书,于2023年7月13日进行修订发布于lyrieek的阿里云开发者社区。

目录
相关文章
|
设计模式 监控 安全
JUC第一讲:Java并发知识体系详解 + 面试题汇总(P6熟练 P7精通)
JUC第一讲:Java并发知识体系详解 + 面试题汇总(P6熟练 P7精通)
4447 0
|
前端开发 网络协议 Dubbo
超详细Netty入门,看这篇就够了!
本文主要讲述Netty框架的一些特性以及重要组件,希望看完之后能对Netty框架有一个比较直观的感受,希望能帮助读者快速入门Netty,减少一些弯路。
95903 33
超详细Netty入门,看这篇就够了!
|
前端开发 JavaScript 测试技术
函数柯里化的应用场景
函数柯里化在编程中广泛应用,如参数复用、提前返回部分计算结果、提高代码可读性和模块化程度。常见于函数式编程语言,也可在JavaScript等语言中实现,简化复杂操作。
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
938 3
python打包pyinstaller如何使用
解决打包时缺失`libpython3.so`的问题,需确保Python在编译时使用`--enable-shared`选项以支持共享库模式。之后,将生成的`libpython3.so`及`libpython3.9.so.1.0`复制到系统库目录`/usr/lib64`。参考链接提供详细步骤。
|
机器学习/深度学习 Serverless 计算机视觉
【YOLOv8改进 - 注意力机制】Sea_Attention: Squeeze-enhanced Axial Attention,结合全局语义提取和局部细节增强
【YOLOv8改进 - 注意力机制】Sea_Attention: Squeeze-enhanced Axial Attention,结合全局语义提取和局部细节增强
|
存储 缓存
解决Gradle: Connection timed out问题
解决Gradle: Connection timed out问题
6400 0
|
机器学习/深度学习 并行计算 PyTorch
从零开始下载torch+cu(无痛版)
这篇文章提供了一个详细的无痛版教程,指导如何从零开始下载并配置支持CUDA的PyTorch GPU版本,包括查看Cuda版本、在官网检索下载包名、下载指定的torch、torchvision、torchaudio库,并在深度学习环境中安装和测试是否成功。
从零开始下载torch+cu(无痛版)
|
Java 调度
java 中sleep 注意点
java 中sleep 注意点
|
Java
Java线程池核心数为0时,线程池如何执行?
【8月更文挑战第11天】Java线程池核心数为0时,线程池如何执行?
720 1