当前位置: 首页 > 科技观察

如何优雅地“中断”你的线程?

时间:2023-03-19 16:55:43 科技观察

最近看了psi-Probe的源码。在主题列表页面,您可以管理每个页面上的主题。有这么一个操作,看到最左边蓝色的彩色框:点击各个线程对应的箭头按钮,会弹出下面的提示:其实按钮的操作就是“杀死”指定的线程。通过链接可以看到具体的实现是这样的:;}if(thread!=null){thread.stop();}正如之前的弹窗提示,这里调用确实是一个危险的操作:Thread中的“stop”方法和“resume”方法。stop()、“挂起”方法和调用线程三,因为线程安全问题,已经@Deprecated。官方文档说得好:停止一个线程会导致它解锁所有它已经锁定的监视器当我们停止一个线程时,它会悄悄地释放它持有的监视器锁。这时,其他依赖锁的线程可能会抢到锁并执行。关键是当前停止线程实际上还没有处理完所有的先决条件,此时可能会出现奇怪的问题,加班的日子可能会悄悄来临。然后你说“不允许停止,我们必须有办法处理线程,即使你通知他,打断他,让他停止。”目前有几种方法可以实现这一点。Thread也想到了异常,提供了一个“异常”来达到中断的目的。该异常在其他线程要中断特定线程时执行,如果满足条件则抛出。这个时候这个特定的线程根据这个中断判断是重新执行线程中的逻辑还是直接跳出处理。这个异常是InterruptedException。一般用法类似try{Thread.sleep(backgroundProcessorDelay*1000L);}catch(InterruptedExceptione){//中断通知后的具体操作}xxxThread.interrupt();目前执行这个操作的方法有以下几种Thread.sleepThread.joinObject.wait以wait方法为例,我们看文档中的描述当*thisexceptionisthrow时清除当前线程。这里有一点信息:“中断状态”,这是一个状态标志,在Thread类中,可以使用isInterrupted来判断当前线程是否被中断。这个标志也可以直接作为退出线程执行的标志。但例外的是阻塞方法接收到中断方法调用后,这个标志位会被清零并重新设置,需要注意。当我们执行阻塞方法线程的中断方法时,此时是无法获取到这个标志的。另外,在获取异常时,需要注意。如果是类似于后台循环执行的调度线程,需要处理异常,然后在收到中断异常时break跳出,否则就是no-op。目前使用这种程序的程序并不多,但下面这几个用的比较多。退出标志对于一些永久线程,有必要在某个时候退出执行。在这种情况下,常用的操作与此类似。以Tomcat的NioConnector中的Acceptor为例:try{Thread.sleep(50);}catch(InterruptedExceptione){//Ignore}}if(!running){break;}...}使用这个退出标志时,记得声明为volatile,像这样:/***端点的运行状态。*/protectedvolatilebooleanrunning=false;/***将在端点暂停时设置为真。*/protectedvolatilebooleanpaused=false;否则,由于多线程可见性问题,该线程可能永远不会退出。目前在Tomcat的使用中,运行时无法直接操作Connector,所以一般情况下可能不会设置暂停标志。但是触发的方式有几种,一种是通过JConsole等工具连接MBeanServer,直接通过它的MBean方法操作pause来改变值,另一种是使用类似psi-Probe(一个强大的Tomcat管理监控tool)Tools)这种管理控制台,我已经把可以操作Connector状态的代码提交到github(如何参与世界上优秀的开源项目?),commiter已经合并。状态变化观察可以使用通常来说,如果担心处理sleep/wait等操作的时间过长,可以使用interrupt来做。对于驻留线程,可以使用退出标志来处理。【本文为专栏作家“侯书城”原创稿件,转载请通过作者微信公众号“Tomcat物语”获得授权】点此查看本作者更多好文