中断的作用:如果线程A正在阻塞,线程B 想要提前结束线程A 的 阻塞状态,则可以通过中断机制来做通知。
java 中断依赖于 3个方法,interrupt(),isInterrupted()和interrupted()。中断状态为true和false
- interrupt() 设置中断状态为true。 A中调用线程B的interrupt()方法,即会向线程B发出信号(线程中断状态已被设置),如果线程B正在执行中没有可以中断的方法,可以通过判断中断状态来决定是否继续执行,这个时候获取中断状态,会返回true,如果线程B是可中断的阻塞状态,则会抛出中断异常。我们可以通过catch 异常进行业务处理。这个时候获取中断状态,会返回false.因为抛出异常的时候,虚拟机清除了中断状态。
- isInterrupted() 用来获取调用线程的中断状态
- interrupted() 是Thread的static方法,用来清除当前线程的中断状态,这个时候获取中断状态,第一次返回的是当前线程的中断状态,第二次返回false. 例如,如果当前线程被中断(没有抛出中断异常,否则中断状态就会被清除),你调用interrupted方法,第一次会返回true。然后,当前线程的中断状态被方法内部清除了。第二次调用时就会返回false。如果你刚开始一直调用isInterrupted,则会一直返回true,除非中间线程的中断状态被其他操作清除了。
另外如果线程B 没有可以中断的方法,被中断了,这个线程需要判断中断状态,然后继续执行,如果处理之后想要清除中断状态,可以调用interrupted() 方法,这样 线程B可以被再次中断。
注意:interrupt()线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。支持线程中断的方法(sleep、wait等 也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。一旦方法抛出InterruptedException,当前调用该方法的线程的中断状态就会被jvm自动清除了,就是说我们调用该线程的isInterrupted 方法时是返回false。如果你想保持中断状态,可以再次调用interrupt方法设置中断状态,然后通过其他逻辑来处理中断。
清除中断状态的方法?
1 线程停止运行 2没有抛出中断异常 3 清除中断状态interrupted()
interrupted 和 isInterrupted的区别?
首先看一下该方法的实现:
public
static
boolean
interrupted () {return
currentThread().isInterrupted(
true
);}
该方法就是直接调用当前线程的isInterrupted(true)方法。
然后再来看一下 isInterrupted的实现:public
boolean
isInterrupted () {return
isInterrupted(
false
);}
这两个方法有两个主要区别:
- interrupted 是作用于当前线程 isInterrupted 是作用于调用该方法的线程对象所对应的线程
- 这两个方法最终都会调用同一个方法,只不过参数一个是true,一个是false;
第二个区别主要体现在调用的方法的参数上,让我们来看一看这个参数是什么含义
先来看一看被调用的方法 isInterrupted(boolean arg)的定义:private
native
boolean
isInterrupted(
boolean
ClearInterrupted);
原来这是一个本地方法,看不到源码。不过没关系,通过参数名我们就能知道,这个参数代表是否要清除状态位。
如果这个参数为true,说明返回线程的状态位后,要清掉原来的状态位(恢复成false)。这个参数为false,就是直接返回线程的状态位。
interrupt()是用来设置中断状态的。返回true说明中断状态被设置了而不是被清除了。
interrupted是静态方法,返回的是当前线程的中断状态。例如,如果当前线程被中断(没有抛出中断异常,否则中断状态就会被清除),你调用interrupted方法,第一次会返回true。然后,当前线程的中断状态被方法内部清除了。第二次调用时就会返回false。如果你刚开始一直调用isInterrupted,则会一直返回true,除非中间线程的中断状态被其他操作清除了。
接下来,看看具体在代码中如何使用。
interrupt()不能中断在运行中的线程,它只能改变中断状态而已。
public class InterruptionInJava implements Runnable{
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava");
//start thread
testThread.start();
Thread.sleep(1000);
//interrupt thread
testThread.interrupt();
System.out.println("main end");
}
@Override
public void run() {
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Yes,I am interruted,but I am still running");
}else{
System.out.println("not yet interrupted");
}
}
}
}
结果显示,被中断后,仍旧运行,不停打印Yes,I am interruted,but I am still running
那么,如何正确中断?
既然是只能修改中断状态,那么我们应该针对中断状态做些什么。
public class InterruptionInJava implements Runnable{
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava");
//start thread
testThread.start();
// Thread.sleep(1000);
//interrupt thread
testThread.interrupt();
System.out.println("main end");
}
@Override
public void run() {
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Yes,I am interruted,but I am still running");
return;
}else{
System.out.println("not yet interrupted");
}
}
}
}
修改代码,在状态判断中如上,添加一个return就okay了。但现实中,我们可能需要做的更通用,不禁又要发出天问,如何中断线程?答案是添加一个开关。
public class InterruptionInJava implements Runnable{
private volatile static boolean on = false;
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava");
//start thread
testThread.start();
Thread.sleep(1000);
InterruptionInJava.on = true;
System.out.println("main end");
}
@Override
public void run() {
while(!on){
if(Thread.currentThread().isInterrupted()){
System.out.println("Yes,I am interruted,but I am still running");
}else{
System.out.println("not yet interrupted");
}
}
}
}
会输出类似结果,这表明是成功中断了的:
这种开关的方式看起来包治百病,但是当遇到线程阻塞时,就会很无奈了,正如下面代码所示:
public class InterruptionInJava implements Runnable{
private volatile static boolean on = false;
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava");
//start thread
testThread.start();
Thread.sleep(1000);
InterruptionInJava.on = true;
System.out.println("main end");
}
@Override
public void run() {
while(!on){
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
System.out.println("caught exception: "+e);
}
}
}
}
线程被阻塞无法被中断。这时候救世主interrupt函数又回来了,它可以迅速中断被阻塞的线程,抛出一个InterruptedException,把线程从阻塞状态中解救出来,show the code。
public class InterruptionInJava implements Runnable{
private volatile static boolean on = false;
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava");
//start thread
testThread.start();
Thread.sleep(1000);
InterruptionInJava.on = true;
testThread.interrupt();
System.out.println("main end");
}
@Override
public void run() {
while(!on){
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
System.out.println("caught exception right now: "+e);
}
}
}
}
结果截图,达到预期。
这种情形同样适用io阻塞,通常io阻塞会立即抛出一个SocketException,类似于上面说的InterruptedException。