kill 掉一个线程,感觉是一件很简单的事情,比如 JAVA 中为我们提供了 stop 方法可以立即终止线程的执行,达到 kill 掉线程的目的。

但实际上对线程的操作是一件精细活,对于一段正在执行的任务,我们不能只是简单粗暴的勒令其停止。原因就是,线程与资源是有关联的。

比如,一个线程持有某个 lock ,我们在线程释放 lock 前粗暴的停止了它的运行,那么可能导致其持有的 lock 永远不能被释放,等待在该 lock 上的其它线程也会永远的阻塞在该处永远无法继续执行。

再比如,一个线程正在进行 IO 操作,占用着硬盘中的某个文件,我们粗暴的终止了该线程,则这个文件便得不到释放,会一直处于被占用状态。

进程是资源分配单位,线程是运行调度单位。但这并不意味着,线程可以不考虑资源的调度随意的执行任务。恰恰相反的是,许多由线程发起申请得到的资源,只有发起申请的线程才能正确的释放它们。因为即使其对同一进程中的其它线程可见,其它线程也并不知道释放该资源的正确时机。

所以我们在终止线程时,不能采用类似 stop 这种简单粗暴的方式。应该确保在终止线程时,线程并不是立即被终止,而是将控制权交给该线程,由该线程自行判断应该做好哪些善后工作,做完这些善后工作后再停止。

JAVA 中的 interrupt 信号可以做到这一点,一个典型的安全终止线程的方式便是基于 interrupt 信号通知线程,以及通过 InterruptedException 异常回滚堆栈钩出阻塞中的线程,使其停止。

关于 JVM 是如何响应 interrupt 信号并抛出 InterruptedException 的,前面的博客有非常全面的解释:https://www.cnblogs.com/niuyourou/p/12392942.html。

我们来看一个 interrupt 终止线程的例子,一个典型的两步终止:

public class ThreadInterrupt extendsThread{

@Overridepublic voidrun(){int i=0;try{while (!Thread.currentThread().isInterrupted()) {

System.out.println("线程进行第 " + i + " 次工作,此时 inerrupt 标志位为:"+Thread.currentThread().isInterrupted());

Thread.sleep(100);

i++;

}//这里可以进行善后工作,比如释放资源

System.out.println("线程接收到 interrupt 信号,离开工作区.此时 inerrupt 标志位为:"+Thread.currentThread().isInterrupted());

}catch(InterruptedException inE){//这里可以进行善后工作,比如释放资源

System.out.println("线程在 sleep 的过程中被 interrupted,此时 interrupt 标志位为:"+Thread.currentThread().isInterrupted());

}

}

}

线程每执行完一次任务,都会检查一下是否有 interrupt 信号,如果有则进行善后工作并退出线程。

同时线程对 InterruptedException 进行了捕获,如果在 sleep/wait/join 过程中收到 interrupt 信号,则回滚堆栈到 try 处,进入 catch 块进行异常的处理,我们可以在catch 块中进行善后工作。

这样无论是运行状态还是阻塞状态(因为 sleep/wait/join 陷入的阻塞,因为我们只有通过这些方法可以使线程陷入阻塞。synchronized 等方法阻塞或唤醒线程是由 JVM 控制的,由 JVM 保证其正确性。)下的线程,都可以及时的响应我们的 interrupt 信号。

我们进行一下测试:

public classTest {public static void main(String[] args) throwsInterruptedException{

Thread test1=newThreadInterrupt();

test1.start();

Thread.sleep(1000);

test1.interrupt();

}

}

看一下效果,在 sleep 过程中接收到了 interrupt 信号:

在正常工作时接收到了 interrupt 信号:

我们可以看到,两次被 interrupt 线程表现并不同。

sleep 情况下进入 catch 块后,interrupt 状态被重置为了 false,而正常状态下被中断时 interrupt 状态未被重置,依然是true。

因为 interrupt 的本质是一个信号,正常情况下我们对一个信号进行了处理应该将其移出信号队列(当然这里不是队列),避免对其重复处理。

sleep 抛出异常前 JVM 帮助我们做到了这一点,我们在对信号进行处理时,也应该手动将其重置。

isInterrupted 只能获取信号状态,不会重置它。interrupted 可以返回信号的当前状态,如果未 true,返回后会将其重置为 false 。我们可以使用 interrupted 方法代替 isInterrupted 方法:

public class ThreadInterrupt extendsThread{

@Overridepublic voidrun(){int i=0;try{while (!Thread.interrupted()) {

System.out.println("线程进行第 " + i + " 次工作,此时 inerrupt 标志位为:"+Thread.currentThread().isInterrupted());

Thread.sleep(1);

i++;

}//这里可以进行善后工作,比如释放资源

System.out.println("线程接收到 interrupt 信号,离开工作区.此时 inerrupt 标志位为:"+Thread.currentThread().isInterrupted());

}catch(InterruptedException inE){//这里可以进行善后工作,比如释放资源

System.out.println("线程在 sleep 的过程中被 interrupted,此时 interrupt 标志位为:"+Thread.currentThread().isInterrupted());

}

}

}

这样再来看效果:

可以看到,在响应了中断信号后,interrupted 方法帮我们将 interrupt 状态重置为了 false。

第 50 次工作时,检测到了 interrupt 信号,但线程还是将其执行完毕后才退出了工作区,这也证实了该方法的可靠性,使线程尽量安全的退出。

java kill线程_如何优雅的 kill 线程相关推荐

  1. java线程的创建线程_多线程(Thread、线程创建、线程池)

    第1章 多线程 1.1 多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序, ...

  2. 线程池默认多少个线程_我需要多少个线程?

    线程池默认多少个线程 这取决于您的应用程序. 但是,对于那些希望对如何从生产站点购买的所有昂贵内核中挤出大量资金的人,请多多包涵,我将阐明围绕多线程 Java应用程序的奥秘. 内容针对最典型的Java ...

  3. weblogic最大线程_处理Weblogic卡住的线程

    weblogic最大线程 定义或什么是缠线?   如果线程 在设定 的时间 内连续工作(非空闲),则WebLogic Server会将其诊断为阻塞 . 您可以通过更改在诊断出线程被阻塞之前的时间长度( ...

  4. junit测试线程_一个在自己的线程中运行测试的JUnit规则

    junit测试线程 有时,能够在单独的线程中运行JUnit测试会很有帮助. 特别是在编写与封装的ThreadLocal或类似对象进行交互的集成测试时,这可能会派上用场. 单独的线程将隐式确保每次测试运 ...

  5. task.run 强制结束线程_图文介绍进程和线程的区别

    点击蓝色"最码农"关注我哟 加个"星标",每天下午18:03,一起学技术 进程和线程的概念 先了解一下操作系统的一些相关概念,大部分操作系统(如Windows. ...

  6. python销毁线程_聊聊 Python 中的线程

    01什么是线程? 线程是操作系统能够进行运算调度的最小单位,它隶属于进程之中,也有人叫它轻量级进程.线程自己没有系统资源,它可与同属一个进程的其它线程共享进程中的资源,同一进程中的多个线程可以并发运行 ...

  7. 线程可以kill吗_还在用 kill -9 停机?这才是最优雅的姿势

    来源公众号Kirito的技术分享 , 作者徐靖峰 最近瞥了一眼项目的重启脚本,发现运维一直在使用 kill-9 的方式重启 springboot embedded tomcat,其实大家几乎一致认为: ...

  8. java 结束程序_如何优雅地停止Java进程

    目录 理解停止Java进程的本质 我们知道,Java程序的运行需要一个运行时环境,即:JVM,启动Java进程即启动了一个JVM. 因此,所谓停止Java进程,本质上就是关闭JVM. 那么,哪些情况会 ...

  9. 所有java程序都有线程_若所有的用户线程都终止了,Java程序就会结束。( )_学小易找答案...

    [单选题]关于链表结构,陈述错误的是 . [单选题]下列关于构造方法的特点的描述中,错误的是 . [判断题]在构造方法中如调用 super() 语句,则必须使其成为构造方法中的第一条语句. [单选题] ...

最新文章

  1. python 图像降噪
  2. 学习Unix/Linux编程要学些什么
  3. python读取xml_python解析xml文件
  4. 怎么进行数据平滑滤波_气相色谱数据处理方法 EWG1990仪器学习网
  5. 在windows下运行spark
  6. 排序算法(1) 快速排序 C++实现
  7. java原生方法,Java Servlet原生调用方法过程简化
  8. mybatis 依赖于jdbc_大数据基础:Mybatis零基础入门
  9. 【10.1】python中的GIL
  10. Linux 2.6内核Makefile浅析
  11. 技术人生:入职半年总结
  12. dom4j解析xml_JAVADom、Sax解析XML详解
  13. 全志F1C100s使用记录:u-boot linux rootfs 编译与烧录测试(基于SD卡)
  14. 代理记账公司如何寻找客户群体,客户群体有那些
  15. apache 启动失败 查看日志
  16. [置顶]定向爬虫 - Python模拟新浪微博登录
  17. 随机生成中文名字的工具类
  18. Python|计算工资
  19. mysql优化总结(四)
  20. 新海诚动漫《天气之子》1080P 4K下载

热门文章

  1. java中final是什么意思_java中final、finali、finally三者之间的区别是什么
  2. (毕业设计资料)基于单片机热敏电阻PT100温度控制系统设计
  3. html网页在手机,HTML5网页设计自适应手机的方法
  4. TTS(1)单片机播放WAV语音,有原理,有代码
  5. GLONASS 系统简介
  6. js requestFullscreen实现全屏功能 浏览器兼容问题解决
  7. 美图秀秀-美化图片之【背景虚化】界面设计
  8. [闪存 1] Flash(闪存)存储器底层原理|闪存存储器重要参数
  9. 从大码美衣讲解电商产品结构--冰山之上
  10. 火影探讨:佐助对决雷影