【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)

这篇具有很好参考价值的文章主要介绍了【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

📋 个人简介

  • 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜
  • 📝 个人主页:馆主阿牛🔥
  • 🎉 支持我:点赞👍+收藏⭐️+留言📝
  • 📣 系列专栏:并发编程🍁
  • 💬格言:要成为光,因为有怕黑的人!🔥
    【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)

前言

今天总结一个设计模式中的属于并发里的一个设计模式,叫两阶段终止模式,看这个名字可能大家都不知道是怎样的,实际上这个就是在考验你对多线程中的interrupt()方法的理解!从而实现线程优雅的退出!本文全是细节,初学者请仔细看,多理解!

interrupt 的理解

来看看jdk手册对于interrupt的介绍:
【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)
还是比较抽象!我结合自己的理解说一说:

Interrupt 这个词很容易让人产生误解。从字面意思来看,好像是说一个线程运行到一半,把它中断了,然后抛出了 InterruptedException 异常,其实并不是!请看下面这段代码:

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个线程 ---我用简洁写法,Thread里面是Runnable接口(是一个函数式接口)的lambda表达式
        Thread t1 = new Thread(()->{
            while(true){
                System.out.println(Thread.currentThread().getName() + "线程运行中...");
            }
        },"t1");
        t1.start();

        // 主线程
        Thread.sleep(1000);  // 让主线程停一会,使得t1线程执行一会
        t1.interrupt();
        System.out.println("interrupt执行啦!");
    }
}

【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)
上面这个代码主线程调用interrupt方法并不会使得线程停止,也没有抛出异常!那么调用这个方法后就什么都没有干嘛,其实不是,它会将打断标记置为true,凭借此打断标记可通过代码判断从而使得线程停止!

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个线程 ---我用简洁写法,Thread里面是Runnable接口(是一个函数式接口)的lambda表达式
        Thread t1 = new Thread(()->{
            while(true){
                System.out.println(Thread.currentThread().getName() + "线程运行中...,打断标记为:"+ Thread.currentThread().isInterrupted());
            }
        },"t1");
        t1.start();

        // 主线程
        Thread.sleep(500);  // 让主线程停一会,使得t1线程执行一会
        t1.interrupt();
        System.out.println("interrupt执行啦!");
    }
}

使用isInterrupted()就可以判断输出线程的打断状态,可以在控制台很清晰的看到,当t1.interrupt()执行后,打断状态从false变为true!

那什么情况下才会抛出InterruptedException异常呢!正如jdk文档中说的,只有sleep,wait,join这三个轻量级阻塞(可以被中断的阻塞,即唤醒线程)声明了InterruptedException异常,可以抛出InterruptedException异常

这也间接说明了interrupt的另一个作用,唤醒阻塞的线程,使得它不再阻塞,转而抛出InterruptedException异常,使得线程顺利执行或者顺利执行完毕,让出cpu的时间片!

我们对上面案例代码进行改变:

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个线程 ---我用简洁写法,Thread里面是Runnable接口(是一个函数式接口)的lambda表达式
        Thread t1 = new Thread(()->{
            while(true){
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + "线程运行中...,打断标记为:"+ Thread.currentThread().isInterrupted());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // 输出在sleep状态被打断后的打断标记
                    System.out.println(Thread.currentThread().isInterrupted());
                }
            }
        },"t1");
        t1.start();

        // 主线程
        Thread.sleep(2000);  // 让主线程停一会,使得t1线程执行一会
        t1.interrupt();
        System.out.println("interrupt执行啦!");
    }
}

【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)
可以看到抛出的异常显示t1线程是在睡眠过程中被打断的,抛出了异常,即唤醒了阻塞线程,使得其继续执行,特别需要注意的是,抛出异常后他的打断标记会重置为false,并不是想像中的true!

isInterrupted() 和 interrupted的区别

interrupted方法是Thread的静态方法,这里就不看jdk文档了,可能读不明白,还会产生误导!
这两个函数都是线程用来判断自己是否收到过中断信号的,前者是非静态函数,后者是静态函数。二者的区别在于,前者只是读取中断状态,不修改状态;后者不仅读取中断状态,还会重置中断标志位!

看下面这个例子:

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个线程 ---我用简洁写法,Thread里面是Runnable接口(是一个函数式接口)的lambda表达式
        Thread t1 = new Thread(()->{
            while(true){
                System.out.println(Thread.currentThread().getName() + "线程运行中...,打断标记为:"+ Thread.interrupted());
            }
        },"t1");
        t1.start();

        // 主线程
        Thread.sleep(500);  // 让主线程停一会,使得t1线程执行一会
        t1.interrupt();
        System.out.println("interrupt执行啦!");
    }
}

【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)

当执行t1.interrupt();后,t1线程打断状态本应该转变为true,但由于调用了Thread.interrupted(),重置了打断状态,因此打断状态一直输出false!

并发设计模式-两阶段终止模式

先来看看两阶段准直模式是啥:

两阶段终止模式是一种并发设计模式,它用于优雅地终止线程。它将终止过程分成两个阶段,第一阶段由线程T1向线程T2发送终止指令,第二阶段是由线程T2响应终止指令。这种模式通过将停止线程这个动作分解为准备阶段和执行阶段这两个阶段,提供了一种通用的用于优雅地停止线程的方法!

所以说,两阶段终止模式的目的是优雅地终止线程,很多人就会产生疑问,不就是停止线程吗,我stop不行吗,为啥要用这模式优雅的停止?

这里主要还是线程安全的问题,相信都看过stop等方法不建议用吧,强行停止线程可能会生成死锁等线程安全问题(停止了,锁未释放,其他线程拿不到锁),优雅地终止线程可以确保线程在终止之前完成它应该完成的任务并执行一些收尾工作,从而保证数据和业务的安全性。如果随意终止线程,可能会导致数据丢失或损坏,或者导致程序运行不稳定。

说了这么多,也看了上面对interupt的介绍,下面就来看看两阶段终止模式的代码实现吧!

package 两阶段终止模式;

/**
 * @Author:Aniu
 * @Date:2023/4/10 21:38
 * @description 并发设计模式-两阶段终止模式-interrupt
 */
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        TwoStageTermination t1 = new TwoStageTermination();
        t1.start();
        Thread.sleep(3000);
        t1.stop();
    }
}

class TwoStageTermination{
    private Thread monitor;

    // 启动线程
    public void start(){
        monitor = new Thread(() -> {
            while(true){
                Thread currentThread = Thread.currentThread();
                // 根据打断标记,退出循环,线程结束
                if(currentThread.isInterrupted()){   // isInterrupted() 打断标记的状态
                    System.out.println("打断标记:true, 线程退出!");
                    break;
                }
                try {
                    Thread.sleep(1000);  // 情况一:睡眠中打断,抛出InterruptedException异常,唤醒线程,清除打断标记:false,需要手动重置打断标记为true
                    System.out.println("线程运行中···"); // 情况二:线程正常运行,打断后,线程不会自动停止,打断标记置为:true,用打断标记写if判断
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    currentThread.interrupt(); // 再次打断:重置打断标记为true,使得循环退出
                }
            }
        });

        monitor.start();
    }

    // 打断线程
    public void stop(){
        monitor.interrupt();   // interrupt() 打断线程
    }
}

【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)
上面有两种情况,一种是在睡眠中打断退出,一种是在运行中打断退出,结合isInterrupted方法实现了线程的优雅退出!

整体流程图如下:
【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)

结语

如果你觉得博主写的还不错的话,可以关注一下当前专栏,博主会更完这个系列的哦!也欢迎订阅博主的其他好的专栏。

🏰系列专栏
👉flask框架入门到实战
👉软磨 css
👉硬泡 javascript文章来源地址https://www.toymoban.com/news/detail-427980.html

到了这里,关于【java 多线程】并发设计模式-两阶段终止模式(对interrupt的理解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++11并发与多线程笔记(7) 单例设计模式共享数据分析、解决,call_once

    程序灵活,维护起来可能方便,用设计模式理念写出来的代码很晦涩,但是别人接管、阅读代码都会很痛苦 老外应付特别大的项目时,把项目的开发经验、模块划分经验,总结整理成设计模式 中国零几年设计模式刚开始火时,总喜欢拿一个设计模式往上套,导致一个小小的

    2024年02月12日
    浏览(41)
  • 【Java中23种设计模式-单例模式2--懒汉式2线程安全】

    加油,新时代打工人! 简单粗暴,学习Java设计模式。 23种设计模式定义介绍 Java中23种设计模式-单例模式 Java中23种设计模式-单例模式2–懒汉式线程不安全 通过运行结果看,两个线程的地址值是相同的,说明内存空间里,创建了一个对象。

    2024年02月20日
    浏览(46)
  • 【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式

    🍎 个人博客: 个人主页 🏆 个人专栏: JAVA ⛳️   功不唐捐,玉汝于成 目录 前言 正文 懒汉式(Lazy Initialization): 双重检查锁定(Double-Checked Locking): 结语 我的其他博客 在软件设计中,单例设计模式是一种重要的设计思想,它确保了一个类只有一个实例,并提供了一

    2024年01月15日
    浏览(55)
  • 【设计模式】详解单例设计模式(包含并发、JVM)

    在软件开发中,经常需要某些类 只能有唯一的实例 ,比如数据库连接。如何才能保证整个应用中只有一个唯一实例?如果靠人为制定的协定来约束,显然不能很好的保证这一点。如果要从 语法上约束 ,在面向对象里面,什么地方能够约束实例的创建? 显然,只有 构造函数

    2024年02月15日
    浏览(36)
  • 设计模式(单例模式,工厂模式),线程池

    目录 什么是设计模式? 单例模式 饿汉模式 懒汉模式 工厂模式 线程池 线程池种类 ThreadPoolExcutor的构造方法: 手动实现一个线程池  计算机行业程序员水平层次不齐,为了 让所有人都能够写出规范的代码, 于是就有了设计模式, 针对一些典型的场景,给出一些典型的解决方案 单例

    2024年02月11日
    浏览(41)
  • 从 Context 看 Go 设计模式:接口、封装和并发控制

    在 Go 语言中, context 包是并发编程的核心,用于传递取消信号和请求范围的值。但其传值机制,特别是为什么不通过指针传递,而是通过接口,引发了我的一些思考。 考虑以下典型的代码片段: 这段代码展示了在 Go 中创建和传递 context 的简单用法。但背后的设计理念和实现

    2024年01月20日
    浏览(42)
  • 设计模式之多线程分工模式--- 生产-消费者模式

    设计模式之避免共享的设计模式Immutability(不变性)模式 设计模式之并发特定场景下的设计模式 Two-phase Termination(两阶段终止)模式 设计模式之避免共享的设计模式Copy-on-Write模式 设计模式之避免共享的设计模式 Thread-Specific Storage 模式 设计模式之多线程版本的if------Guarde

    2024年01月16日
    浏览(35)
  • Arch - 多线程设计架构模式

    多线程设计架构模式是一种通过合理地使用线程来提高系统性能和响应能力的设计模式。以下是一些常见的多线程设计架构模式: 线程池模式:通过预先创建一组线程,将任务提交到线程池中执行,避免了线程的频繁创建和销毁,提高了系统的性能和稳定性。 生产者-消费者

    2024年02月16日
    浏览(38)
  • <JavaEE> 经典设计模式之 -- 线程池

    目录 一、线程池的概念 二、Java 标准库中的线程池类 2.1 ThreadPoolExecutor 类 2.1.1 corePoolSize 和 maximumPoolSize 2.1.2 keepAliveTime 和 unit 2.1.3 workQueue 2.1.4 threadFactory 2.1.5 handler 2.1.6 创建一个参数自定义的线程池 2.2 Executors 类 2.3 实现自己的线程池 1)什么是线程池? 准备预期需要使

    2024年02月05日
    浏览(33)
  • 设计模式之多线程分工模式--- Thread-Per-Message模式

    设计模式之避免共享的设计模式Immutability(不变性)模式 设计模式之并发特定场景下的设计模式 Two-phase Termination(两阶段终止)模式 设计模式之避免共享的设计模式Copy-on-Write模式 设计模式之避免共享的设计模式 Thread-Specific Storage 模式 设计模式之多线程版本的if------Guarde

    2024年02月01日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包