有线程运行,肯定就会有线程中断,在Java语言中,线程中断是一种协作机制,通过对线程设置中断标记,告知对应的线程,根据中断标记来决定是否需要中断当前线程。也就是说,在线程运行过程中,其实我们没有办法安全,准确的终止一个线程。
设置线程中断标志,所在线程调用该方法之后,正常情况下会设置一个线程中断标志位 interrupt = true.(此时调用interrupted或者是isInterrupted就会返回true),如果该线程处于等待,阻塞,或者无限期等待状态,那么就会抛出InterruptedException异常,从而提前结束线程。但是不能中断I/O阻塞和synchronized锁阻塞。
sleep方法
Thread thread = new Thread(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
会抛出异常 java.lang.InterruptedException: sleep interrupted
wait方法
public class InterruptTest {
private static String str = "test";
public static void main(String[] args) {
Thread thread = new Thread(()->{
synchronized (str){
try {
str.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
thread.interrupt();
}
}
抛出异常:java.lang.InterruptedException
join方法
Thread thread1 = new Thread(()->{
while (true){
}
});
Thread thread = new Thread(()->{
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread.start();
thread.interrupt();
抛出异常:java.lang.InterruptedException
synchronized锁阻塞测试:
public class InterruptTest {
private static String str = "test";
public static void main(String[] args) {
Thread thread2 = new Thread(() -> {
synchronized (str) {
while (true){
}
}
});
thread2.start();
thread2.interrupt();
System.out.println(thread2.isInterrupted());
Thread.sleep(1000);
Thread thread3 = new Thread(() -> {
synchronized (str) {
System.out.println("拿到锁了");
}
});
thread3.start();
thread3.interrupt();
System.out.println(thread3.isInterrupted());
}
}
//运行结果
true
true
结果分析:不管是在已经获取到锁,执行业务代码的时候还是在未获取到锁,等待获取锁的过程中,即使调用了interrupt方法,将当前线程中断标志置为true,当前线程既不会被中断,也不会抛出InterruptedException。 在测试中,为了保证测试的线程在执行interrupt方法执行之前已经处于运行状态,建议让主线程阻塞一段时间
返回一个线程打断标记,布尔类型。
对于上面的sleep,wait,join这种被打断的线程,这个方法会返回false,意思是调用了sleep,wait,join这类方法,会将打断标记清除,在某一时刻是true,但是最终是false。以sleep为例
Thread thread1 = new Thread(()->{
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
// 在这里打印当前线程的状态一定是false
//System.out.println(Thread.currentThread().isInterrupted());
}
});
thread1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread1.isInterrupted());
thread1.interrupt();
System.out.println(thread1.isInterrupted());
//运行结果
false
false //这里也有可能打印true
java.lang.InterruptedException: sleep interrupted
上面的运行结果第二行,也就是当我调用了interrupt方法之后立即调用isInterrupted方法,这里有可能会是true, 原因在于当sleep方法抛出异常的时候,才将线程的中断状态置为false,当调用了interrupt方法的时候,线程状态为true。
对于正常的一直在运行的线程,调用了interrupt方法之后,不会清除打断标记。
Thread thread = new Thread(()->{
while(true){
}
});
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.isInterrupted());
thread.interrupt();
System.out.println(thread.isInterrupted());
//运行结果
false
true
线程会一直运行下去,不会受到线程中断的影响,即使中断标志位为true。但是我们可以根据线程中断标志,来判断当前线程是否可以继续运行。
对线程稍微改造一下,让他在线程中断为true的时候退出线程运行。
Thread thread = new Thread(()->{
while(true){
if(!Thread.currentThread().isInterrupted()){
System.out.println("线程该中断了!做完这一点活就退休");
System.out.println("再干一点点");
break;
}
}
});
其他运行代码不变,看运行结果
这是一个静态方法,用的比较少。其实原理和isInterrupted是差不多的,区别在于isInterrupted不会清除中断标志,interrupted会将中断标志清除,也就是说,我们调用了isInterrupted 之后,对于正常在执行的线程,他的中断标志一直是true,但是我们调用了interrupted方法之后,只有在执行了interrupt之后到我们执行interrupted之前为true,在之后就是false。
JDK源码中的解释:测试当前线程是否被中断。该方法清除线程的中断状态。换句话说,如果这个方法被连续调用两次,第二次调用将返回 false(除非当前线程再次被中断,在第一次调用清除其中断状态之后,第二次调用检查它之前)。由于在中断时线程不活动而被忽略的线程中断将通过此方法返回 false 来反映。
线程中断对于我们学习多线程还是有很大的帮助,线程中断本质上不会强制将线程停止,如果需要强制将线程终止,可以调用Thread 中的stop()方法,但是不建议这么用,该方法已经过时,学习了线程中断,我们就可以根据线程中断标志来更加优雅的停止线程。
文中有错误的地方也希望大佬们能指出来