如何优雅的「打断」你的线程?

作者:CQITer小编 时间:2018-06-24 21:26

字号
技术沙龙 | 6月30日与多位专家探讨技术高速发展下如何应对运维新挑战!

最近看了点 psi-Probe的源代码,在线程列表页面,可以对页面中各个进行线程管理,其中有这样一个操作,见最左侧蓝色方框:

如何优雅的「打断」你的线程?

点击每个线程对应的箭头按钮,会弹出下方的提示:

如何优雅的「打断」你的线程?

实际这上按钮的操作,是要 「Kill」这个指定的线程。

顺着链接,我们能看到,具体的实现是这个样子:

String threadName = ServletRequestUtils.getStringParameter(request, "thread", null); 

 

Thread thread = null

if (threadName != null) { 

  thread = Utils.getThreadByName(threadName); 

 

if (thread != null) { 

  thread.stop(); 

正如前面的弹窗提示,这里果然调用的是个危险操作:

Thread.stop() 

这里的 「stop」方法,和「resume」方法、「suspend」方法并称 Thread 三少,因为线程安全问题,都已经被 @Deprecated 了。

官方文档说的好:

Stopping a thread causes it to unlock all the monitors that it has locked  

当我们停止一个线程时,它会悄悄的把所持有的 monitor 锁释放了,此时,其他依赖锁的线程可能就会抢到锁执行。关键此时,当前 stop 的线程实际并没有处理完所有先决条件,可能这个时候就产生了诡异的问题,加班的日子可能就悄悄来了。

那你说 「Stop 不让用了,总得让我们有办法处理线程吧,哪怕通知他,打断他一下,让他停止」。

目前有以下几种方式来实现。

异常

这点 Thread 也想到了,提供了一个「异常」来达到这个打断的目的。这个异常在其他线程要打断某个特定线程时执行,如果是符合条件,会抛出来。此时这个特定线程自行根据这次打断来判断后续是不是要再执行线程内的逻辑,还是直接跳出处理。

这个异常就是 InterruptedException。一般使用方式类似这样

try { 

    Thread.sleep(backgroundProcessorDelay * 1000L); 

} catch (InterruptedException e) { 

    // 具体在中断通知后的操作 

     

 xxxThread.interrupt();   

目前有以下方法能够进行这种操作

Thread.sleep

Thread.join

Object.wait

以wait方法为例,我们来看文档里的描述

* @throws  InterruptedException if any thread interrupted the 

*             current thread before or while the current thread 

*             was waiting for a notification.  The <i>interrupted 

*             status</i> of the current thread is cleared when 

*             this exception is thrown. 

这里有一点信息: 「interrupted status」,这个是个状态标识,在Thread类中,可以通过 isInterrupted来判断当前线程是否被中断。这个标识也可以用来作为一个退出线程执行的标识来直接使用。 但例外是阻塞方法在收到中断方法调用后,这个标识会被清除重置,所以需要注意下。

我们在执行阻塞方法线程的interrupt方法时,此时并不能拿到这个标识。

另外,拿到异常时,需要关注,如果是类似于后台循环执行的调度线程,在收到中断异常时需要处理异常再 break 才能跳出,否则只是相当于一个空操作。

目前一些程序里用这种的倒不多,用下面这种的多一些。

退出标识

对于一些长驻线程,会在某些时候需要退出执行,这种情况下,常采用的操作类似这样, 以Tomcat 的NioConnector 里的Acceptor为例:

protected class Acceptor extends AbstractEndpoint.Acceptor { 

 

    @Override 

    public void run() { 

 

        int errorDelay = 0

 

        // Loop until we receive a shutdown command 

        while (running) {   // 标识1 

 

            // Loop if endpoint is paused 

            while (paused && running) {   // 标识2 

责任编辑:CQITer新闻报料:400-888-8888   本站原创,未经授权不得转载
关键词 >>线程 Tomcat 多线程
继续阅读
热新闻
推荐
关于我们联系我们免责声明隐私政策 友情链接