zoukankan      html  css  js  c++  java
  • 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){}

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

  • 相关阅读:
    C++笔试题库之编程、问答题 150~200道
    C++语言中的static关键字的作用是什么?
    C++开发工程师面试题库 1~50道
    C++笔试题库之编程、问答题 100~150道
    C++经典面试题库 附带参考答案
    常用的16个c/c++面试题
    C++经典面试题全集 50~100道 都附带有参考答案
    c++常见面试题30道
    别傻了,人家离职你也离
    西苑附近的一亩园社区
  • 原文地址:https://www.cnblogs.com/codeToSuccess/p/13906197.html
Copyright © 2011-2022 走看看