interrupt方法打断线程demo
1.打断非阻塞状态的线程
package com.demo;
public class InterruputDemo {
public static void main(String[] args) throws InterruptedException {
demo1();
}
/**
*1.在main线程中调用子线程的interrupt方法,子线程中无阻塞方法
*/
private static void demo1() throws InterruptedException {
//子线程
Thread t2 = new Thread(() -> {
int count = 0;
//开始时,中断标志为false,进入循环
while (!Thread.currentThread().isInterrupted()) {
System.out.println("子线程运行中。。。" + count++);
System.out.println("子线程运行中。。。1");
System.out.println("子线程运行中。。。2");
System.out.println("子线程运行中。。。3");
System.out.println("子线程运行中。。。4");
System.out.println("子线程运行中。。。5");
System.out.println("子线程运行中。。。6");
}
//当main中调用了interrupt,中断标志变为true,退出循环
System.out.println("子线程中断标志="+Thread.currentThread().isInterrupted());
});
t2.start();
//主线程
int count = 0;
while (true) {
//睡眠1秒,等待子线程进入睡眠
Thread.sleep(1000);
t2.interrupt();
System.out.println("main运行中。。。" + count++);
}
}
}
运行结果:
子线程运行中。。。6
子线程运行中。。。7333
子线程运行中。。。1
子线程运行中。。。2
子线程运行中。。。3
子线程运行中。。。4
子线程运行中。。。5
子线程运行中。。。6
子线程运行中。。。7334
子线程运行中。。。1
子线程运行中。。。2
子线程运行中。。。3
子线程运行中。。。4
main运行中。。。0
子线程运行中。。。5
子线程运行中。。。6
子线程中断标志=true
main运行中。。。1
main运行中。。。2
main运行中。。。3
main运行中。。。4
main运行中。。。5
main运行中。。。6
main运行中。。。7
结论:
-
调用了另一个线程的interrupt方法后,会将它的中断标志位设置为false(没有抛出InterruptedException 的情况下);
-
被打断的线程除了标志位发生变化,没有任何改变。若没有其他操作,将会顺利执行完毕线程中的代码。
2.打断阻塞状态的线程
package com.demo;
public class InterruputDemo {
public static void main(String[] args) throws InterruptedException {
demo2();
}
/**
*打断线程的睡眠状态
*/
public static void demo2() throws InterruptedException {
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("子线程运行中。。。");
//睡眠30秒
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
//当另一个线程(main线程)调用了本线程的interrupt方法后,若本线程正在sleep则会抛出InterruptedException异常,否则啥也不会发生;
//只有声明了InterruptedException异常的方法才会抛出这个异常;
//InterruptedException被抛出后,我们检查当前线程的阻塞状态,发现是false
boolean interrupted1 = Thread.currentThread().isInterrupted();//false
System.out.println("子线程的中断状态1=" + interrupted1);
Thread.currentThread().interrupt();
boolean interrupted2 = Thread.currentThread().isInterrupted();//true
System.out.println("子线程的中断状态2=" + interrupted2);
}
}
});
t.start();
int count = 0;
while (true) {
//睡眠1秒,等待子线程进入睡眠
Thread.sleep(1000);
t.interrupt();
System.out.println("main运行中。。。" + count++);
}
}
}
运行结果:
子线程运行中。。。
main运行中。。。0
子线程的中断状态1=false
子线程的中断状态2=true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.demo.InterruputDemo.lambda$demo2$0(InterruputDemo.java:19)
at java.lang.Thread.run(Thread.java:748)
main运行中。。。1
main运行中。。。2
main运行中。。。3
main运行中。。。4
结论:
- 打断阻塞状态sleep中的线程,sleep方法会抛出InterruptedException异常;
- 抛出InterruptedException异常时,线程的中断标志会重新设置为false;
- 要想通过判断中断标志退出线程循环,需要在catch中再调用一次interrupt将中断标志设置为true。这时线程并不在阻塞状态,不会抛出异常。
总结:
- 中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断。
- Thread.interrupt()方法不会中断一个正在运行的线程。
- 如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该Thread类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个InterruptedException异常。这个时候,我们可以通过捕获InterruptedException异常来终止线程的执行,具体可以通过return等退出或改变共享变量的值使其退出。
- synchronized在获锁的过程中是不能被中断的,意思是说如果产生了死锁,则不可能被中断(请参考后面的测试例子)。与synchronized功能相似的reentrantLock.lock()方法也是一样,它也不可中断的,即如果发生死锁,那么reentrantLock.lock()方法无法终止,如果调用时被阻塞,则它一直阻塞到它获取到锁为止。但是如果调用带超时的tryLock方法reentrantLock.tryLock(long timeout, TimeUnit unit),那么如果线程在等待时被中断,将抛出一个InterruptedException异常,这是一个非常有用的特性,因为它允许程序打破死锁。你也可以调用reentrantLock.lockInterruptibly()方法,它就相当于一个超时设为无限的tryLock方法。