java更加优雅并且主动控制线程中断

一、stop()方法

说到中断线程,我们首先会想到用stop()方法,但是这个方法已经被官方废弃了,下面是官方的解释:

《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》

为什么弃用stop:

  1. 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
  2. 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。

所以我们想要中断线程就不能够使用stop()方法。

二、interrupt()方法

使用interrupt()方法真的就是中断线程了吗?并不是!此方法并不是像stop()一样暴力的中断了线程的执行,只是会给线程一个标志,告诉线程可以进行中断了,但何时中断是由线程自己控制的。

下面让我们看下interrupt()的例子:

public class InterruptedTask implements Runnable{

    @Override
    public void run() {

        Thread currentThread = Thread.currentThread();
        while (true){
            if(currentThread.isInterrupted()){
                break;
            }

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class InterruptedTest {
    public static void main(String[] args){
        InterruptedTask interruptedTask = new InterruptedTask();
        Thread interruptedThread = new Thread(interruptedTask);
        interruptedThread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        interruptedThread.interrupt();
    }
}

在这里插入图片描述
运行结果如上,可以看出线程并没有退出,为什么会这样呢???

Thread.sleep() 方法会抛出一个 InterruptedException 异常,当线程被 sleep() 休眠时,如果被中断,这会就抛出这个异常。并且Thread.sleep() 方法由于中断而抛出的异常,是会清除中断标记的,”currentThread.isInterrupted()“就变为false了,所以就永远不会中断线程了,那我们应该如何来中断线程呢?

问题解决

正确的处理方式应该是在InterruptedTask类中的run()方法中的while(true)循环中捕获异常之后重新设置中断标志位,所以,正确的InterruptedTask类的代码如下所示。

public class InterruptedTask implements Runnable{

    @Override
    public void run() {

        Thread currentThread = Thread.currentThread();
        while (true){
            if(currentThread.isInterrupted()){
                break;
            }

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
                currentThread.interrupt();
            }
        }
    }
}

可以看到,我们在捕获InterruptedException异常的catch代码块中新增了一行代码。

currentThread.interrupt();

这就使得我们捕获到InterruptedException异常后,能够重新设置线程的中断标志位,从而中断当前执行的线程。

我们再次运行InterruptedTest类的main方法,如下所示。
在这里插入图片描述
可以看出线程已经被正确的中断了。

总结

处理InterruptedException异常时要小心,如果在调用执行线程的interrupt()方法中断执行线程时,抛出了InterruptedException异常,则在触发InterruptedException异常的同时,JVM会同时把执行线程的中断标志位清除,此时调用执行线程的isInterrupted()方法时,会返回false。此时,正确的处理方式是在执行线程的run()方法中捕获到InterruptedException异常,并重新设置中断标志位(也就是在捕获InterruptedException异常的catch代码块中,重新调用当前线程的interrupt()方法)。

有没有更加优雅并且我们可以主动控制的中断线程的方法呢?有!使用标志位终止线程。

三、标志位中断线程

有时候,我们希望自己可以主动控制线程的中断,而不是由线程自己来控制,这时我们就可以使用自定义的标志位来控制线程是否中断,比如在服务端程序中可能会使用 while(true) { ... } 这样的循环结构来不断的接收来自客户端的请求。此时就可以用修改标志位的方式来结束 run() 方法。

public class ServerThread extends Thread {
    //volatile修饰符用来保证其它线程读取的总是该变量的最新的值
    public volatile boolean exit = false; 

    @Override
    public void run() {
        ServerSocket serverSocket = new ServerSocket(8080);
        while(!exit){
            serverSocket.accept(); //阻塞等待客户端消息
            ...
        }
    }
    
    public static void main(String[] args) {
        ServerThread t = new ServerThread();
        t.start();
        
        ...(进行一些其他逻辑操作)
            
        t.exit = true; //修改标志位,退出线程
    }
}

由上面代码可以看出,在main()方法中进行了一些列逻辑判处断后,设置exit为true时,run方法中的while(!exit){…}循环变为false,此时就退了run方法,中断了该线程。

这样就优雅并且主动的由我们控制何时来中断线程,可以更好的满足我们的业务需求,而不是由线程本身去控制,因为有时候对于我们可能是不可控的,主动权还是要掌握在我们自己手中的。

总结

上面总结了三种中断线程的方法,第一种stop()方法已经被官方废弃,不推荐使用。第二种interrupt()方法是设置线程标志位,但是何时中断是由线程自己控制的,主动权不在我们自己手中。第三种设置中断标志位,这种方法可以有我们主动控制,可以根据业务需求,选着何时中断线程,这样更满足我们业务的定制化需求。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值