搜索
写经验 领红包
 > 教育

java线程中断(java引起线程中断的常见原因)

导语:Java面试精讲-线程中断

问题:请问什么叫做线程中断?为什么不能使用stop方法中断线程?

问题解析:

在正常的线程生命周期中,线程中断一直都不是一个正常的状态。

那么什么是线程中断呢?

我们先从sleep方法开始介绍。我们都知道,如果我们想要调用thread.sleep()方法,必须要求我们catch一个InterruptedException。这个InterruptedException异常,就是由线程中断造成的。

当线程运行到一个不可控制的状态的时候,我们想尝试结束他,这个时候,使用线程的stop方法或suspend方法(这两个都是经典线程方法),但都是非常不安全的,比如调用stop方法,该方法会立刻,马上终止当前线程,就有可能造成本来还在该线程正常锁同步的内容突然破坏,让本该保护的变量被其他线程可见。虽然这个时候会抛出一个特殊的ThreadDeath()异常,但这个异常是没法被正常处理的,就有可能让其他线程消费到错误的数据。所以该方法被标记为过期。

简单的例子,比如A线程正在执行代码:

synchronized {

x = 3;

y = 4;

}

本来代码块是synchronized标记的,保证x和y总是同时能被赋值,但假如A线程执行到x=3代码的时候,突然调用了stop方法,A线程立刻被杀死,导致出现了一个潜在的不安全的数据。这个就是stop的问题所在。

到这里,第二个问题解决,为什么不能使用stop方法中断线程。

那么,我们再深入考虑一步(这也是BATJ常见的提问方式)怎么该怎么安全的中断线程呢?有多种办法,其中一种就是调用Thread.interrupt方法。interrupt方法,是一种安全的中断线程方法。

问题继续,那什么是interrupt方法?该方法有什么特征?

interrupt方法,是告诉线程,我需要中断你,但是一定注意,该方法调用之后,线程并不会立刻终止(否则就变成stop了),而是在合适的时机终止。什么时机呢?Java的处理判定机制为:

A情况:如果该线程处在可中断状态下,(调用了xx.wait(),或者Thread.sleep()等特定会发生阻塞的api),那么该线程会立即被唤醒,同时会收到一个InterruptedException,如果是阻塞在io上,对应的资源会被关闭。

B情况:如果该线程处在不可中断状态下,就是没有调用上述api,那么java只是设置一下该线程的interrupt状态,其他事情都不会发生,如果该线程之后会调用行数阻塞API,那到时候线程会马会上跳出,并抛出InterruptedException,接下来的事情就跟第一种状况一致了。如果不会调用阻塞API,那么这个线程就会一直执行下去。除非你就是要实现这样的线程,一般高性能的代码中肯定会有wait(),yield()之类出让cpu的函数,不会发生后者的情况。

意思就是说,interrupt方法,主要可以用于中断两种情况的线程:

1,中断处于运行中的线程;

2,中断处于阻塞中的线程;

例一:线程正常执行某个逻辑,条件改变,需要取消任务执行:

该示例中,在main方法启动MyThread1线程, 线程正常执行,3秒之后,对MyThread1线程发起中断请求。在MyThread1线程run方法中,循环检查中断标识,Thread.currentThread().isInterrupted()一但监测到线程中断请求,立马终止循环,结束线程(该示例匹配B情况,需要配合isInterrupted方法来判定标记位【具体查看最后一个问题】)。

例二:线程休眠等待条件满足,当条件提前满足,马上中断休眠,开始执行

该示例代码中,在main方法中启动MyThread2线程,线程开始执行,遇到sleep方法然后阻塞10s,此时的main方法阻塞3s时间到,醒来调用interrupt()给MyThread2线程设置了请求中断标识(true),与此同时,MyThread2立马醒来,先将中断标识复位(false), 然后抛出一个中断异常InterruptedException 。这里要注意,在catch中需要对线程再发起一次中断请求,否则逻辑又进入修改状态(该流程匹配模式B,可立刻被处理中断)。

最后一个问题,那么interrupt方法如何实现的呢?

原理很简单:Java 会给每一个线程都设置一个boolean类型中断标识,用来标明当前线程是否请求中断。当线程对象调用interrupt() 方法时,会将当前线程标识置为true。表示请求中断此线程。 注意此时仅仅是标记要中断,如何执行中断,根据上述模式A和模式B执行。

本文内容由快快网络小璎创作整理编辑!