Java:一个停止线程的方法——interrupt

一、前言

之前本人写了一篇防止Controller中的线程被重复调用的文章,大概代码如下:

//sonarqube检查要求static变量必须是final,为避开检查,使用final HashMap
public final static HashMap<String,Thread> threadMap = new HashMap<>();
--------------------------------------------------
Thread nowThread = threadMap.get("nowThread");
if(nowThread != null && nowThread.isAlive()){
    LOG.info("当前存在正在执行的线程,本次线程不执行,请稍后再试");
    return;
}

else{
    threadMap.put("nowThread",Thread.currentThread());
}
//主要代码省略
......

//线程执行完毕,置空
threadMap.put("nowThread",null);

后来,由于担心这个线程会卡死,导致后续正常调用该线程的操作无法进行,因此加了个手动停止线程运行的方法(interrupt):

//传入一个type参数,如果为3,中断上一个线程的执行
if(type == 3){
 try{
   Thread nowThread = threadMap.get("nowThread");
   //中断上一个线程
   nowThread.interrupt();
   threadMap.put("nowThread",null);
   String backMsg = "线程interrupt成功!";
   LOG.info(backMsg);
   return;
 }catch(Exception e){
   threadMap.put("nowThread",null);
   String backMsg = "线程interrupt失败,只将map置空!";
   LOG.error(backMsg,e);
   return;
 }
}

然而,仅仅这样并不能停止线程运行。

二、停止线程运行的方法

  1. 使用标志位停止线程,还行,但是遇到sleep时的线程就无法停止了,必须等线程sleep结束、运行到判断标志位步骤时才行。

  2. 使用stop()停止线程,不安全,已不推荐使用。会立即停止线程运行,会使一些清理性的工作的得不到完成,如文件,数据库等的关闭;会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。

  3. 使用interrupt()中断线程,需要配合代码逻辑实现停止线程。

需要注意,调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程;如果直接将线程停止,就会和stop一样出现问题。

因此还需要配合代码逻辑实现。

三、正确使用interrupt停止线程运行

先看下例子:

public static void main(String[] args) throws InterruptedException{
  Thread t1 = new Thread(){
    @Override
    public void run(){
      //一个循环线程
      while(true){
        //一种结束情况
        if(this.currentThread().isInterrupted()){
          System.out.println("线程被打断,停止运行");
          break;
        }else{
          System.out.println("线程在运行");
          try{
            //Thread.sleep(0L);
            Thread.sleep(1000L);
          }catch(InterruptedException e){
            //另一种结束情况
            System.out.println("线程睡眠时被打断,停止运行");
            break;
          }
        }
      }
    }
  };
  t1.start();
  Thread.sleep(5000L);
  t1.interrupt();
  System.out.println("主线程打断t1完成");
}

上方的代码中,先启动一个线程,然后主线程在5秒后打断它,它有两种停止情况:

  1. 执行if判断时,发现标志位为true,因此执行break,之后停止运行。

  2. 线程还在sleep,此时发现被打断,会抛出InterruptedException,然后被catch到,执行break,之后停止运行。

结合实际代码,如果线程中不需要sleep,则判断isInterrupted()即可;

如果线程中存在sleep,则catch中使用break、return之类的停止线程即可;

当然也可以两种都写。

本人的代码中有sleep,因此只在catch中加了break,没有判断标志位。

四、总结

  1. 使用interrupt停止线程比标志位停止线程的好处在于,它不仅能通过标志判断是否要停止线程,而且当线程处于sleep状态时,使用interrupt就可以停止线程,而标志位不行。

  2. 使用interrupt停止线程比stop停止线程的好处在于,stop不安全,会产生难以预料的后果,而interrupt不会。

  3. 停止线程时,不仅要直接调用interrupt(),还要写好相应的代码逻辑,一种逻辑与标志位停止线程类似,另一种逻辑要注意在try中写Thread.sleep(当你的线程需要sleep时),在catch中写break、return之类的方法。

PS:之前写sleep时,都是这么写的:

try{
 Thread.sleep(5000L);
}catch(Exception e){}

现在终于知道应该怎么写了……

原文地址:https://www.cnblogs.com/codeToSuccess/p/13906197.html