线程中断方法interrupt、isInterrupted、interrupted方法

简介: 线程中断方法interrupt、isInterrupted、interrupted方法

微信截图_20230224215627.png


Thread.currentThread().interrupt()


该方法为非静态方法,该方法的作用:标记线程为中断状态,仅仅是标记


/**
 * @author chaird
 * @create 2020-12-22 13:58
 */
public class Main {
  public static void main(String[] args) {
    // 获取当前线程
    Thread currentThread = Thread.currentThread();
    // 获取当前线程的中断状态
    System.out.println(currentThread.isInterrupted()); // false
    // 标记为中断线程
    currentThread.interrupt();
    // 获取当前线程的中断状态
    System.out.println(currentThread.isInterrupted()); // true
  }
}


Thread.currentThread().isInterrupted()


该方法为非静态方法,该方法的作用:返回线程的中断状态


/**
 * @author chaird
 * @create 2020-12-22 13:58
 */
public class Main {
  public static void main(String[] args) {
    // 获取当前线程
    Thread currentThread = Thread.currentThread();
    // 获取当前线程的中断状态
    System.out.println(currentThread.isInterrupted()); // false
    // 标记为中断线程
    currentThread.interrupt();
    // 获取当前线程的中断状态
    System.out.println(currentThread.isInterrupted()); // false
  }
}


Thread.interrupted()


/**
 * @author chaird
 * @create 2020-12-22 13:58
 */
public class Main {
  public static void main(String[] args) {
    // 获取当前线程
    Thread currentThread = Thread.currentThread();
    // 获取当前线程的中断状态
    System.out.println(currentThread.isInterrupted()); // false
    // 标记为中断线程
    currentThread.interrupt();
    // 获取当前线程的中断状态
    System.out.println(currentThread.isInterrupted()); // false
    // (1)获取当前线程的中断状态,(2)并且取消中断状态
    boolean interrupted = Thread.interrupted();
    System.out.println(interrupted); // true
    System.out.println(currentThread.isInterrupted()); // false 。因为Thread.interrupted()中取消中断状态
  }
}


如何正确的中断一个正在执行的线程


案例1:没有坑并且不带Sleep的代码


import java.time.LocalDateTime;
/**
 * @author chaird
 * @create 2020-12-22 14:15
 */
public class Start {
  public static void main(String[] args) {
    InterruptedTask interruptedTask = new InterruptedTask();
    Thread interruptedThread = new Thread(interruptedTask);
    interruptedThread.start();
    try {
      // 睡1秒
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    // 设置线程为中断状态
    interruptedThread.interrupt();
  }
}
class InterruptedTask implements Runnable {
  @Override
  public void run() {
    Thread currentThread = Thread.currentThread();
    while (true) {
      if (currentThread.isInterrupted()) {
        break;
      }
      System.out.println("LocalDateTime:" + LocalDateTime.now().toString());
    }
  }
}


案例2:有坑并且带Sleep的代码


下述代码明明调用了线程的interrupt()方法来中断线程,但是却并没有起到啥作用。原因是线程的run()方法在执行的时候,大部分时间都是阻塞在sleep(100)上,当其他线程通过调用执行线程的interrupt()方法来中断执行线程时,大概率的会触发InterruptedException异常,在触发InterruptedException异常的同时,JVM会同时把线程的中断标志位清除,所以,这个时候在run()方法中判断的currentThread.isInterrupted()会返回false,也就不会退出当前while循环了。


import java.time.LocalDateTime;
/**
 * @author chaird
 * @create 2020-12-22 14:15
 */
public class Start {
  public static void main(String[] args) {
    InterruptedTask interruptedTask = new InterruptedTask();
    Thread interruptedThread = new Thread(interruptedTask);
    interruptedThread.start();
    try {
      // 睡1秒
      Thread.sleep(500);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    // 设置线程为中断状态
    interruptedThread.interrupt();
  }
}
class InterruptedTask implements Runnable {
  @Override
  public void run() {
    Thread currentThread = Thread.currentThread();
    while (true) {
      if (currentThread.isInterrupted()) {
        break;
      }
      System.out.println("LocalDateTime:" + LocalDateTime.now().toString());
      try {
        // 睡0.1秒
        Thread.sleep(100);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}


解决办法


import java.time.LocalDateTime;
/**
 * @author chaird
 * @create 2020-12-22 14:15
 */
public class Start {
  public static void main(String[] args) {
    InterruptedTask interruptedTask = new InterruptedTask();
    Thread interruptedThread = new Thread(interruptedTask);
    interruptedThread.start();
    try {
      // 睡1秒
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    // 设置线程为中断状态
    interruptedThread.interrupt();
  }
}
class InterruptedTask implements Runnable {
  @Override
  public void run() {
    Thread currentThread = Thread.currentThread();
    while (true) {
      if (currentThread.isInterrupted()) {
        break;
      }
      System.out.println("LocalDateTime:" + LocalDateTime.now().toString());
      try {
        // 睡0.1秒
        Thread.sleep(100);
      } catch (InterruptedException e) {
        e.printStackTrace();
        // 在触发InterruptedException异常的同时,JVM会同时把线程的中断标志位清除,所以需要复现中断状态
        currentThread.interrupt();
      }
    }
  }
}


案例3:有坑,需要JMM知识解决


主线程睡0.5秒,然后去中断interruptedThread线程,但是运行下面的代码线程并没有结束,说明有BUG


/**
 * @author chaird
 * @create 2020-12-22 14:15
 */
public class Start {
  public static void main(String[] args) {
    InterruptedTask interruptedTask = new InterruptedTask();
    Thread interruptedThread = new Thread(interruptedTask);
    interruptedThread.start();
    try {
      // 睡0.5秒
      Thread.sleep(500);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    interruptedTask.myInterrupted();
  }
}
class InterruptedTask implements Runnable {
  private boolean sign = false;
  @Override
  public void run() {
    Thread currentThread = Thread.currentThread();
    while (!sign) {}
  }
  public void myInterrupted() {
    sign = true;
  }
}


解决办法


因为InterruptedTask里的while(true)太快了,没有任何逻辑,所以一个字:快。


虽然JMM中主内存中的更新了数据,但是本地内存来不及去主内存中更新数据,所以上面的案例中InterruptedTask里的sign一直都是false。volatile可以解决内存可见性。这就是另一个知识点了,不多解释。


private boolean sign = false
改为
private volatile boolean sign = false;


注意


本文中说的中断状态其实就是一个标志位,而不是真正的中断线程


class MyThread {
  // 中断状态标志位
  private volatile boolean sign = false;
}
目录
相关文章
|
4月前
|
存储 Oracle Java
|
6月前
|
Java
创建线程的方法
Java中实现多线程有四种方式:1. 继承Thread类,简单但占用继承机会,耦合度高;2. 实现Runnable接口,推荐方式,任务与线程解耦,支持Lambda;3. 实现Callable接口配合FutureTask,可获取返回值和异常;4. 使用线程池(ExecutorService),企业推荐,管理线程生命周期,提升性能,支持多种线程池类型。
158 1
|
7月前
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
494 5
|
监控 Java
捕获线程执行异常的多种方法
【10月更文挑战第15天】捕获线程执行异常的方法多种多样,每种方法都有其特点和适用场景。在实际开发中,需要根据具体情况选择合适的方法或结合多种方法来实现全面有效的线程异常捕获。这有助于提高程序的健壮性和稳定性,减少因线程异常带来的潜在风险。
304 57
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
Java 程序员 调度
【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)
创建线程的五种方式,Thread常见方法(守护进程.setDaemon() ,isAlive),start和run方法的区别,如何提前终止一个线程,标志位,isinterrupted,变量捕获
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
275 3
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
154 2
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
203 1
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
348 1

热门文章

最新文章