Java并发编程 interrupt()方法示例详解

 更新时间:2023年06月09日 16:13:19   作者:k3ruanren  
interrrupt()方法可以用来打断正在运行的线程,也可以打断sleep()、wait()、join()情况下的线程,但是这些情况下被打断线程的打断标记不同,这篇文章主要介绍了Java并发编程 interrupt()方法示例详解,需要的朋友可以参考下

interrupt()用法

打断正常运行的线程

interrrupt()方法可以用来打断正在运行的线程,也可以打断sleep()、wait()、join()情况下的线程,但是这些情况下被打断线程的打断标记不同。

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class InterruptTest {
    public static void main(String[] args) throws InterruptedException {
        //创建一个线程
        Thread t1 = new Thread(() -> {
            //让线程一直死循环运行
            log.debug("t1开始运行.....");
            while(true){
            }
        },"t1");
        //启动线程t1
        t1.start();
        //main主线程一秒后进行打断操作
        TimeUnit.MILLISECONDS.sleep(1000);
        log.debug("interrupt.....");
        t1.interrupt();
    }
}

通过控制台,可以很清晰的看到,main主线程在执行完打断操作后,t1线程并未终止运行,而是继续执行:

但是如果我们查看线程t1的打断标记会发现,t1线程的打断标记确实为true:

Boolean interrupted = Thread.currentThread().isInterrupted();

这是因为main主线程执行interrupt打断操作,只是通知t1线程,我现在要打断你,但是具体的执行操作还得看t1线程,即t1线程收到main主线程的打断通知后,由t1线程自己觉得是继续运行还是被打断,从而让出cpu,这样的好处在于线程t1如果在执行某些很重要的任务,突然被其他线程强制打断可能会造成很严重的后果,这时可以让t1线程自己选择是否停止工作,也可以在停止工作之前做一些料理后事的工作 。

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class InterruptTest {
    public static void main(String[] args) throws InterruptedException {
        //创建一个线程
        Thread t1 = new Thread(() -> {
            //让线程一直死循环运行
            log.debug("t1开始运行.....");
            while(true){
                Boolean interrupted = Thread.currentThread().isInterrupted();
                //选择被打断后的执行操作
                if(interrupted){
                    log.debug("被打断,停止运行...");
                    break;
                }
            }
        },"t1");
        //启动线程t1
        t1.start();
        //main主线程一秒后进行打断操作
        TimeUnit.MILLISECONDS.sleep(1000);
        log.debug("interrupt.....");
        t1.interrupt();
    }
}

14:41:02.906 [t1] DEBUG InterruptTest - t1开始运行.....
14:41:03.908 [main] DEBUG InterruptTest - interrupt.....
14:41:03.908 [t1] DEBUG InterruptTest - 被打断,停止运行...

打断sleep状态的线程

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class InterruptTest {
    public static void main(String[] args) throws InterruptedException {
        //创建一个线程
        Thread t1 = new Thread(() -> {
            //让线程一直死循环运行
            log.debug("t1开始运行.....");
            //t1线程休眠3秒
            try {
                log.debug("t1 is sleeping...");
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"t1");
        //启动线程t1
        t1.start();
        //main主线程一秒后进行打断操作
        TimeUnit.MILLISECONDS.sleep(1000);
        log.debug("interrupt.....");
        t1.interrupt();
        //查看t1线程的打断标记
        Boolean interrupted = t1.isInterrupted();
        log.debug(interrupted.toString());
    }

打断sleep状态的线程,会抛出InterruptedException异常,并且打断标记是false而不是true:

14:50:25.532 [t1] DEBUG InterruptTest - t1开始运行.....
14:50:25.536 [t1] DEBUG InterruptTest - t1 is sleeping...
14:50:26.533 [main] DEBUG InterruptTest - interrupt.....
14:50:26.544 [main] DEBUG InterruptTest - false
Exception in thread "t1" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted
	at InterruptTest.lambda$main$0(InterruptTest.java:17)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at java.base/java.lang.Thread.sleep(Thread.java:334)
	at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446)
	at InterruptTest.lambda$main$0(InterruptTest.java:15)
	... 1 more
Process finished with exit code 0

两阶段终止模式 Two Phase Termination

在线程t1中如何优雅的终止线程t2?

  • 使用stop()方法终止线程,这显然是不好的行为,因为一个线程调用了stop()方法,那么这个线程就被彻底杀死了,如果该线程正在访问一些共享资源并且加了锁,那么stop()之后该线程将再也不能释放锁,其他线程也就无法访问那些共享资源了。
  • 使用System.exit()方法,这也是错误的选择,这会终止整个程序!

正确的做法是采用两阶段终止模式,具体流程如下图所示:

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class TwoPhaseTest {
    public static void main(String[] args) throws InterruptedException {
        TwoPhaseTermination tpt = new TwoPhaseTermination();
        tpt.start();
        TimeUnit.SECONDS.sleep(4);
        tpt.stop();
    }
}
/**
 * 监控类
 */
@Slf4j
class TwoPhaseTermination{
    //监控线程
    private Thread monitor;
    //线程启动方法
    public void start(){
        monitor = new Thread(()->{
            while(true){
                Thread thread = Thread.currentThread();
                Boolean interrupted = thread.isInterrupted();
                if(interrupted){
                    log.debug("料理后事.....");
                    break;
                }
                try {
                    TimeUnit.SECONDS.sleep(1);
                    //每隔一秒钟执行监控任务
                    log.debug("监控中....");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //如果在sleep状态被打断,那么中断标记为false,需要手动置为true
                    thread.interrupt();
                }
        }});
        //启动线程
        monitor.start();
    }
    //线程终止方法
    public void stop(){
        //打断线程
        monitor.interrupt();
    }
}

15:38:11.046 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
15:38:12.054 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
15:38:13.060 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
java.lang.InterruptedException: sleep interrupted
    at java.base/java.lang.Thread.sleep(Native Method)
    at java.base/java.lang.Thread.sleep(Thread.java:334)
    at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446)
    at TwoPhaseTermination.lambda$start$0(TwoPhaseTest.java:33)
    at java.base/java.lang.Thread.run(Thread.java:829)
15:38:14.014 [Thread-0] DEBUG TwoPhaseTermination - 料理后事.....

Process finished with exit code 0

打断park()线程

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
@Slf4j
public class ParkTest {
    public static void main(String[] args) throws InterruptedException {
        test();
    }
    private static void test() throws InterruptedException {
        Thread t1 = new Thread(()->{
           log.debug("park......");
           LockSupport.park();//线程在此卡住,不继续向下执行
           log.debug("unpark.......");
           log.debug("打断状态:{}",Thread.currentThread().isInterrupted());
        },"t1");
        t1.start();
        //主线程main休眠2秒
        TimeUnit.SECONDS.sleep(2);
        //打断t1线程
        t1.interrupt();
    }
}

15:51:24.581 [t1] DEBUG ParkTest - park......
15:51:26.582 [t1] DEBUG ParkTest - unpark.......
15:51:26.584 [t1] DEBUG ParkTest - 打断状态:true

到此这篇关于Java并发编程 interrupt()方法的文章就介绍到这了,更多相关Java并发编程 interrupt()方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • GateWay路由规则与动态路由详细介绍

    GateWay路由规则与动态路由详细介绍

    这篇文章主要介绍了GateWay路由规则与GateWay动态路由,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • springboot集成flyway自动创表的详细配置

    springboot集成flyway自动创表的详细配置

    Flayway是一款数据库版本控制管理工具,支持数据库版本自动升级,Migrations可以写成sql脚本,也可以写在java代码里;本文通过实例代码给大家介绍springboot集成flyway自动创表的详细过程,感兴趣的朋友一起看看吧
    2021-06-06
  • SpringBoot整合MinIO实现文件存储系统的代码示例

    SpringBoot整合MinIO实现文件存储系统的代码示例

    在现代的应用程序中,文件存储和管理是一个常见的需求,MinIO是一个开源的对象存储系统,与Spring Boot框架结合使用,可以快速构建高性能的文件存储系统,本文将介绍如何使用Spring Boot和MinIO来实现文件存储系统
    2023-06-06
  • Spring Boot 实现Restful webservice服务端示例代码

    Spring Boot 实现Restful webservice服务端示例代码

    这篇文章主要介绍了Spring Boot 实现Restful webservice服务端示例代码,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-11-11
  • spring-boot-maven-plugin:unknown的完美解决方法

    spring-boot-maven-plugin:unknown的完美解决方法

    这篇文章主要介绍了spring-boot-maven-plugin:unknown的完美解决方法,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • 使用System.exit()来优雅地终止SpringBoot项目的代码示例

    使用System.exit()来优雅地终止SpringBoot项目的代码示例

    System.exit() 方法是 Java 中用于退出程序的方法,它接受一个整数参数,通常被用来指示程序的退出状态,本文给大家介绍了如何使用System.exit()来优雅地终止SpringBoot项目,需要的朋友可以参考下
    2024-08-08
  • postman测试传入List<String>参数方式

    postman测试传入List<String>参数方式

    这篇文章主要介绍了postman测试传入List<String>参数方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java类成员访问权限控制知识总结

    Java类成员访问权限控制知识总结

    这篇文章主要介绍了Java类成员访问权限控制知识总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Mybatis实现动态建表代码实例

    Mybatis实现动态建表代码实例

    这篇文章主要介绍了Mybatis实现动态建表代码实例,解释一下,就是指根据传入的表名,动态地创建数据库表,以供后面的业务场景使用,
    而使用 Mybatis 的动态 SQL,就能很好地为我们解决这个问题,需要的朋友可以参考下
    2023-10-10
  • spring的xml文件打开没有namespace等操作选项的解决方案

    spring的xml文件打开没有namespace等操作选项的解决方案

    这篇文章主要介绍了spring的xml文件打开没有namespace等操作选项的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09

最新评论