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){}

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

  • 相关阅读:
    poj 1860 Currency Exchange(最短路径的应用)
    poj 2965 The Pilots Brothers' refrigerator
    zoj 1827 the game of 31 (有限制的博弈论)
    poj 3295 Tautology (构造法)
    poj 1753 Flip Game(枚举)
    poj 2109 (贪心)
    poj 1328(贪心)
    Qt 对单个控件美化
    Qt 4基础
    Bash Shell
  • 原文地址:https://www.cnblogs.com/codeToSuccess/p/13906197.html
Copyright © 2011-2022 走看看