Java线程中断
Java线程里:“中断”就是指“终止”,与操作系统里的"中断"、“异常”是完全不同的概念;
由于stop()方法过于暴力,可能导致资源回收无法风险、开销过大等问题,此方法已过期,故Java中没有强制中断线程的手段;但可以调用interupt()、interupted()方法来向进程提出中断请求,待进程自行处理,这是一种更优雅的中断方式。
注意:当需要中断线程时,最佳实践就是利用线程的中断位,而不是自定义中断状态,因为当线程被阻塞时,原生中断位仍然会被监听,而自定义的则不能。
以下两类场景会应用到线程中断:
- 用来打断正在阻塞的线程:阻塞在sleep/wait/join等方法上、 阻塞在io-channel读写操作上、阻塞在io-channel-selector上。
- 打断正常执行的线程:需要在目标线程内部检测中断位,并由用户手动终止,来做出响应。
- interrupt()
实例方法,在线程内外都可发起调用;其作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。)作用于正常执行线程时会将中断标记设置为true,但作用于阻塞线程时则会将中断标志重置为false(中断标记的默认初始值为false)。 - interrupted()
静态方法,只能在线程内部调用;作用是测试当前线程是否被中断(检查中断标志),返回一个boolean并重置中断状态,第二次再调用时中断状态已经被重置,将返回一个false。
- interrupt()
- isInterrupted()
作用是只检测此线程是否被中断 ,不修改中断状态。
- 不在线程内部检测中断位并手动响应中断,线程将无限执行下去:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
System.err.println("子线程");
}
});
thread.start();
System.out.println("---" + thread.isInterrupted()); // ---false
/**
* 这里主线程只是将子线程的中断位改为了true
* 由于子线内部并没有就中断位进行检测和处理,故子线程并不会终止,会无限地打印下去
*/
thread.interrupt();
TimeUnit.SECONDS.sleep(1);
System.err.println("===" + thread.isInterrupted()); // ===true
}
- 在非阻塞线程内部手动响应中断(这里主要是观察中断位的状态):
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().isInterrupted());
System.err.println("子线程");
}
});
thread.start();
System.out.println("---" + thread.isInterrupted()); // ---false
/**
* 这主线程只是改变了子线程的中断位改为了true
*/
TimeUnit.SECONDS.sleep(3);
thread.interrupt();
System.err.println("===" + thread.isInterrupted()); // ===true
}
- 在非阻塞线程内部手动响应中断:
/**
* 当子线程需要响应主线程的中断请求,而停止时。可以通过在子线程中实时检测其自身的中断状态来达到停止的目的
*
* @param args
*/
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
// 实时检测自身中断状态
while (!Thread.currentThread().isInterrupted()) {
System.err.println("子线程");
}
});
thread.start();
TimeUnit.SECONDS.sleep(2);
// 修改子线程的中断状态
thread.interrupt();
}
- 中断阻塞中的线程:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// 异常被捕获后,阻塞被打破、中断位被重置为false,所以下面中永远输出false
System.out.println("2 ----" + Thread.currentThread().isInterrupted()); // 2 ----false
System.err.println("回收资源");
e.printStackTrace();
// 注意,这里一定要再次将中断位设为true,否则不能终止外面的while循环
Thread.currentThread().isInterrupt();
}
System.err.println("子线程逻辑");
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
System.out.println(thread.isInterrupted()); // true
TimeUnit.SECONDS.sleep(5);
}
- 优雅中断非阻塞线程:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
if (Thread.interrupted()) {
System.out.println("清理资源");
break;
}
System.err.println("子线程逻辑");
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
}
学习使我充实,分享给我快乐!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)