当前位置: 首页 > news >正文

java InterruptedException

背景
题主在写代码的是否,使用sleep()方法,方法抛出了这个异常,为了如何妥善处理这个异常,有了下面的总结。

在了解InterruptedException异常之前应该了解以下的几个关于线程的一些基础知识。而且得知道什么时候会抛InterruptedException异常(当阻塞方法收到中断请求的时候就会抛出InterruptedException异常)

1 什么是中断

线程中断(Thread Interruption)是 Java 中一种协调多线程应用中线程间通信和协作的机制。中断是一个线程通过【标记】来通知另一个线程,它应该停止当前在做的事情并尽快退出。线程中断机制提供了一种优雅和建议的方式来停止或通知线程。被通知的线程在适当的时候自我检查,决定是否终止、暂停或者进行其他处理。

工作原理和方法

线程通过设置一个内部的中断标志位来表示它是否已经被通知中断,默认为false,表示未被中断。当一个线程A调用了线程B的interrupt()方法时,那么线程B的是否请求的中断标志变为true,而线程B可以调用方法检测到此标志的变化。相关的方法有

t.interrupt()发出中断信号给线程t,设置t的中断标志为true。启动中断不会强行停止线程,而是通知线程应该停止执行,这种通知其实只是更改了线程的标志位而已,具体是否停止线程是由具体的逻辑决定的。
t.isInterrupted()检查线程t是否有中断状态,但不清除中断标志,就是不会修改重点标识。
Thread.interrupted()静态方法,返回并重置当前线程的中断状态,设置中断状态为true。用于线程操作检查和重置状态。

本质上,上面的方法就是在查看和更改标识位的值。

2 什么是中断异常 InterruptedException

【阻塞方法】收到中断请求的时候抛出的异常就是中断异常InterruptedException

为了理解阻塞方法要先说下面几个概念:

2.1线程的状态

线程在一定的条件下会发生状态的改变,下面是线程的一些状态

  • 初始(NEW):新建一个线程的对象,还未调用start方法
  • 运行(RUNNABLE):java线程中将已经准备就绪(Ready)和正在运行中(Running)的两种状态都统称为“Runnable”。准备就绪的线程会被放在线程池中等待被调用
  • 阻塞(BLOCKED):是因为各种原因进入了无法获取锁,无法获取CPU的使用权,暂时的停止了运行。直到线程获取锁,才会进入准备就绪(Ready)状态才会有机会转到运行状态
  • 等待(WAITING):该状态的线程需要等待其他线程做出一些特定的动作(通知或者是中断)
  • 超时等待(TIME_WAITING):该状态和上面的等待不同,他可以在指定的时间内自行返回
  • 终止(TERMINATED):线程任务执行完毕

2.2 线程阻塞

线程阻塞通常是指一个线程在执行过程中暂停,以等待某个条件的触发。而什么情况才会使得线程进入阻塞的状态呢?

  • 等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒
  • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中
  • 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态

2.3阻塞方法

阻塞方法:就是会抛出InterruptedException异常的方法。

如果线程B调用了阻塞方法+中断标志变为了true,那么它会抛出InterruptedException异常。抛出异常的同时它会将线程B的是否请求中断标志置为false。

抛InterruptedException的代表方法有:sleep(),wait(),join()。

这三个方法在执行过程中会不断轮询中断状态,如果中断=true,从而自己抛出InterruptEdException。

2.4代码示例

package com.autonavi.cloudmap.xd.biz.impl;

/**
 * @program: Test
 * @description:
 **/
public class InterrupTest implements Runnable{

    public void run(){
            try {
                while (true) {
                    Boolean a = Thread.currentThread().isInterrupted();
                    System.out.println("in run() - about to sleep for 20 seconds -" + a);
                    Thread.sleep(20000);
                    System.out.println("in run() - woke up");
                }
            } catch (InterruptedException e) {
                System.out.println("1"+Thread.currentThread().isInterrupted());
                Thread.currentThread().interrupt();
                System.out.println("2"+Thread.currentThread().isInterrupted());
                Boolean c=Thread.interrupted();
                System.out.println("c="+c);
                System.out.println("3"+Thread.currentThread().isInterrupted());
                Boolean d=Thread.interrupted();
                System.out.println("d="+d);
                System.out.println("4"+Thread.currentThread().isInterrupted());
            }
    }
    public static void main(String[] args) {
        InterrupTest si = new InterrupTest();
        Thread t = new Thread(si);
        t.start();
        //主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间
        try {
            Thread.sleep(2000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("in main() - interrupting other thread");
        //中断线程t
        t.interrupt();
        System.out.println("in main() - leaving");
    }
}

返回结果:
 

in run() - about to sleep for 20 seconds-------false
in main() - interrupting other thread
in main() - leaving
1false
2true
c=true
3false
d=false
4false

Process finished with exit code 0


 

3 对InterruptedException异常的处理

在实际处理中,sleep(),wait(),join()本身会抛出InterruptedException,对这个异常的处理本质是对中断状态的处理。

1、没有基于中断信息的逻辑处理

如果是在单线程或多线程没有对中断进行通讯和控制的相关内容,打日志或者对线程中断状态进行具体的控制其实没什么区别,因为并不关心这个中断状态的信息有什么用。这里推荐的方式是,catch后,恢复中断状态为true,以防未来这个中断信息有需要的时候。

2、有基于中断信息的逻辑处理

在具体需要根据线程的中断状态进行控制的情况下,就可以按照逻辑需要,通过Thread.interrupted();将中断状态改为自己需要的值。在后续具体的逻辑里进行程序的处理和终止等操作。

不推荐catch后向上抛出,虽然可以转换为RuntimeException抛出,但是有几个不好的点:首先这样中断了线程的执行。如果目标就是中断线程,应该利用中断信息位做更优雅的操作;其次,抛出RuntimeException也屏蔽了具体的中断细节,在多层调用结构里,会造成难以定位问题的问题。

4、代码示例

1. 检查中断标志位时结束运行

线程可以在适当的地方检查自己的中断状态,并在检测到中断时自行退出。常用的方法是 Thread.currentThread().isInterrupted()

public class InterruptExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Thread is running...");
                // 执行一些任务
                try {
                    Thread.sleep(1000); // sleep 会响应中断并抛出异常
                } catch (InterruptedException e) {
                    System.out.println("Thread is interrupted during sleep.");
                    Thread.currentThread().interrupt(); // 恢复中断状态以便进一步检查
                }
            }
            System.out.println("Thread is exiting...");
        });

        thread.start();
        Thread.sleep(3000); // 让线程运行一段时间
        thread.interrupt(); // 发送中断信号
    }
}

明确的任务中断检查和资源清理

复杂任务中必须在多个地方进行中断检查,并进行必要的资源清理。

public class ComplexTaskExample {
    public static void main(String[] args) {
        Thread thread = new Thread(new ComplexTask());

        thread.start();

        try {
            Thread.sleep(3000); // 主线程休眠3秒
            thread.interrupt(); // 中断任务线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ComplexTask implements Runnable {
    @Override
    public void run() {
        try {
            performTask1();
            performTask2();
            performTask3();
        } catch (InterruptedException e) {
            System.out.println("Task was interrupted.");
            // 执行必要的清理资源
            cleanUp();
        }
        System.out.println("Task exiting...");
    }

    private void performTask1() throws InterruptedException {
        System.out.println("Performing Task 1");
        // 处理过程,如果中断
        if (Thread.currentThread().isInterrupted()) {
            throw new InterruptedException();
        }
    }

    private void performTask2() throws InterruptedException {
        System.out.println("Performing Task 2");
        // 模拟阻塞
        Thread.sleep(2000);
    }

    private void performTask3() throws InterruptedException {
        System.out.println("Performing Task 3");
        // 处理过程,如果中断
        if (Thread.currentThread().isInterrupted()) {
            throw new InterruptedException();
        }
    }

    private void cleanUp() {
        System.out.println("Cleaning up resources...");
    }
}

参考链接:
Java线程状态分析/线程状态转换图_jdk 线程状态图-CSDN博客必须要掌握的 InterruptedException 异常处理-腾讯云开发者社区-腾讯云

InterruptedException异常处理方式-CSDN博客

相关文章:

  • 武汉地铁计划建设在哪个网站查可以做产品推广的软件有哪些
  • 吉林企业网站模板建站哪个好中国纪检监察报
  • cpanel伪静态wordpress天津seo排名扣费
  • 国外设计工作室西安seo优化排名
  • 做3dmax的网站推广网页
  • 苏州网站设计公司济南兴田德润厉害吗网络推广的调整和优化
  • 从零开始写android 的智能指针
  • vue watch 和 watchEffect的区别和用法
  • C++:日期类,运算符重载,深浅拷贝问题
  • python:面向对象之包
  • 2025.04.10-拼多多春招笔试第四题
  • MySQL的半同步模式
  • 中间件-消息队列
  • 网络3 子网掩码 划分ip地址
  • h265为什么没有大范围应用
  • C/C++共有的类型转换与c++特有的四种强制类型转换
  • MySQL——存储过程、索引
  • 融智学三大定律:打开人机协同智慧大门的钥匙
  • 深度分页及优化建议
  • 【前端】【难点】前端富文本开发的核心难点总结与思路优化
  • 飞书集成衡石ChatBot实战:如何10分钟搭建一个业务数据问答机器人?
  • 期望理论解析
  • MCP基础学习三:MCP客户端开发与工具集成
  • linux系统编程里面的嵌套锁
  • 强化学习算法系列(二):Model-Free类方法——蒙特卡洛算法(MC)和时序差分算法(TD)
  • Linux 多线程