一 体系化深入学习并发编程由简入繁系统梳理并发知识点( 四 )


java.lang.InterruptedException: sleep interrupted
同时,在run方法内,使用sleep方法时,也会被要求对异常进行捕捉处理,默认则是这个异常,而我们没有对捕捉到的异常进行操作,所以默认打印出来栈轨迹
那么如果是在循环内部执行sleep方法呢?
这是第一种情况
try {while (num<=100){if (num%10==0){System.out.println(num);}num++;Thread.sleep(10);}}
可以看见的是,我们不再需要进行.().()这个判断了,因为一旦阻塞状态被打断,就会跳转到catch,这个判断是否被打断的判断语句则失效了
接下来是第二种情况
我们把try/catch代码块整个搬进循环内部
while (num <= 100) {if (num % 10 == 0) {System.out.println(num);}num++;try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}
结果是:在出现异常之后,while循环并没有停止,继续打印
那么是不是因为while没有判定到终止条件呢?于是我同时又加上了是否被打断的判断
while (!Thread.currentThread().isInterrupted() && num <= 100)
很遗憾的是,结果依然没有发生改变,我并没有真正地停止这个线程,它任然我行我素,直到打印完所有数字 。
这是因为:在sleep方法被打断的时候,抛出异常的同时,清除了被打断的标记,所以再次检测该线程时,是显示没有被打断的
中断异常的处理方式
第一种:自己解决,重新恢复中断
因为上述问题是sleep被打断抛出异常后,清除了中断标志导致的,那么我们是不是可以恢复中断呢
public void reInterrupt(){try {Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();e.printStackTrace();}}
当发生了阻塞线程被中断时,我们并不是生吞该异常,而是将该线程重新标记为,这样可以在调用该方法时检测到
run方法中调用方法
@Overridepublic void run() {while (true&&!Thread.currentThread().isInterrupted()){System.out.println("exception");reInterrupt();}}
执行该线程,可以看到,当出现异常时,跳出了循环,程序中断了
public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(new RightWayWhenInterruptInvalid2());thread.start();Thread.sleep(1000);thread.interrupt();}
第二种:抛出异常,传递中断
假如我们在调用一个方法是如下定义的,同样使用了try/catch,但是并没有重新设置为中断状态
public void throwAnException(){try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}
那么它并没有做出任何处理,只是打印栈轨迹,生吞了该异常
而我们在run方法中使用该方法后
@Overridepublic void run() {while (true){System.out.println("exception");throwAnException();}}
只会打印错误信息在控制台,而不会有其他的逻辑操作,如果实际数据量上去了,那么这个打印的信息,就可能被淹没在日志文件中,我们很难发现这个问题 。
所以正确的方式是,在方法声明时,就抛出该异常
public void throwAnException() throws InterruptedException
而在run方法中,我们就必须使用try/catch代码块来处理该异常,因为run方法是顶层函数,它无法再向上抛出异常了,所以必须自己处理,这样,run方法调用了方法,它就需要来处理这个异常