写在前面:
之前在一篇博客中介绍了线程中断的相关内容(http://blog.youkuaiyun.com/may_3/article/details/79393281),在Java锁的实现中也有使用中断的地方,所以想用一篇博客再好好总结一下线程的中断。
中断:
- 概念:
中断是线程的一个标识位属性,表示运行中的线程是否对其他线程进行了中断操作。其他线程是通过interrupt方法来中断线程。
- 应用场景:
比如:当一个线程A调用sleep方法,进入睡眠状态,等待1s,等待线程B完成,但如果其他线程B提前完成,想要线程A提前结束睡眠状态,就会调用该线程的interrupt方法,中断线程A。
- Interrupt方法:
(1) 对于非阻塞的线程,调用Interrupt方法只会改变线程的中断标识位,即Thread.isInterrupted()会返回true
(2) 对于可从阻塞状态中取消的线程(比如:线程调用了Thread.sleep/Thread.join/Object.wait等)调用Interrupt方法,程序会抛出一个InterruptedException异常,同时将中断状态置回为true(调用Thread.Interrupted可以对中断状态复位)。
- IsInterrupted方法:
IsInterrupted方法会检查线程是否中断,并返回一个boolean,且不会清楚中断标志位。是对象的方法,调用方式Thread.currentThread.IsInterrupted().
- Interrupted方法:
Interrupted方法同样会返回中断标志位,并重置标志位。
- 中断的类型
(1)中断非阻塞方法
中断非阻塞方法,只是更改了标识位,并不影响程序的运行。
package test3;
public class InterruptDemo {
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadDemo1(), "线程1");
thread1.start();
try {
Thread.sleep(2000);// 主线程睡眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
thread1.interrupt();
}
}
class ThreadDemo1 implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName());
}
if (Thread.currentThread().isInterrupted()) {
System.out.println("被中断");
}
}
}
(2)中断阻塞方法
当线程调用了wait、sleep、join方法时,线程会进入阻塞状态,对线程进行中断,会提前结束阻塞状态(并不会改变中断的状态),并且抛出一个InterruptedException。
代码:
package test3;
public class InterruptDemo {
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadDemo1(), "线程1");
thread1.start();
try {
Thread.sleep(1000);// 主线程睡眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
thread1.interrupt();
}
}
class ThreadDemo1 implements Runnable {
@Override
public void run() {
try {
Thread.sleep(2000);// 子线程睡眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("子线程的中断状态为" + Thread.currentThread().isInterrupted());
}
}
}
我们来分析一下代码的实现过程:
(1)首先子线程启动,主线程睡眠1秒,这时子线程一直处于睡眠即阻塞状态。
(2)当主线程醒来,对睡眠中的子线程中断,子线程停止阻塞状态,并会抛出一个InterruptedException异常。此时打印当前线程的中断状态为false。注:说明中断阻塞状态的线程不会改变中断状态。
(3)后面如果还有代码,仍然会正常执行。
(3)不可中断线程。
当线程被synchronized修饰或者处于reentrantLock.lock()获取锁的过程中,则线程不可以被中断。但我们可以使用超时tryLock方法来对线程中断,即ReentrantLock.tryLock(longtimeout, TimeUnit unit),中断后,会抛出一个InterruptedException异常。