如何触发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的阿里云开发者社区。

目录
相关文章
|
6天前
|
设计模式 Java 调度
多案例理解Object的wait,notify,notifyAll与Thread的sleep,yield,join等方法
多案例理解Object的wait,notify,notifyAll与Thread的sleep,yield,join等方法
46 1
|
8月前
Exception in thread “main“ 主线程异常的解决方法
Exception in thread “main“ 主线程异常的解决方法
516 0
|
6天前
|
监控 算法 Unix
Thread.sleep(0) 到底有什么用
Thread.sleep(0) 到底有什么用
25 1
|
11月前
|
监控
Sleep()和wait()方法的区别
Sleep()和wait()方法的区别
78 0
|
调度 C++
Thread.sleep(0) vs Thread.sleep(1) vs Thread.yield() vs Object.wait()
Thread.sleep(0) vs Thread.sleep(1) vs Thread.yield() vs Object.wait()
|
Java 调度 C++
你真的了解Thread.sleep(0)吗?以及Thread.sleep(1) vs Thread.sleep(0)
你真的了解Thread.sleep(0)吗?以及Thread.sleep(1) vs Thread.sleep(0)
|
消息中间件 安全 Java
|
Java
简述Thread的interrupt()、interrupted()及isInterrupted()的区别
简述Thread的interrupt()、interrupted()及isInterrupted()的区别
120 0
简述Thread的interrupt()、interrupted()及isInterrupted()的区别
|
安全 Java 中间件
Thread.sleep(0)的作用
在源码中经常能看到sleep(0)的操作,今天来总结下sleep(0)的作用到底是啥
389 0