设计模式之保护性暂停

news2024/11/24 8:37:12

文章目录

    • 1. 定义
    • 2. 实现保护性暂停模式
    • 3. Join原理
    • 4. 保护性暂停模式的扩展

1. 定义

即Guarded Suspension,用在一个线程等待另一个线程的执行结果。

  • 有一个结果需要从一个线程传递给另一个线程,让他们关联到同一个GuarderObject(这就是保护性暂停模式,是两个线程之间交换结果的模式)
  • 如果有结果不断从一个线程到另一个线程可以使用消息队列(这个是生产者-消费者模式)
  • JDK中,Join实现,Futrue的实现,采用的就是此模式
  • 因为要等待另一方的结果,因此归类到同步模式

在这里插入图片描述

2. 实现保护性暂停模式

实现这个模式的关键是GuardedObject,response属性是用来保存中间结果。所以我们使用wait-notify来实现保护性暂停模式。

实现保护对象

class  GuardedObject{
    private Object response;
    //获取结果
    public Object get() {
        synchronized (this){
            while(response==null){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return  response;
        }
    }

    public void complete(Object response){
        synchronized (this){
            this.response=response;
            this.notify();
        }
    }
}

案例场景,线程1等待线程二的下载结果

public class jvm {
   public static List<String> downLoad() throws IOException {
       HttpURLConnection connection= (HttpURLConnection) new URL("https://www.baidu.com/").openConnection();
       List<String> list=new ArrayList<>();
       try(BufferedReader reader=new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))){
           String line;
           while((line= reader.readLine())!=null){
               list.add(line);
           }
       }
       return list;
   }

    public static void main(String[] args) {
       GuardedObject guardedObject=new GuardedObject();
        new Thread(()->{
            log.debug("等待结果");
            List<String> list= (List<String>) guardedObject.get();
            log.debug("结果大小,[{}]",list.size());
        },"线程1").start();
        new Thread(()->{
            log.debug("执行下载");
            try {
                List<String> list=downLoad();
                guardedObject.complete(list);
            } catch (IOException e) {
                e.printStackTrace();
            }
        },"线程2").start();
    }
}

在这里插入图片描述

3. Join原理

Join底层原理就是基于这种保护性暂停的模式,首先我们来看看Join的底层源码

public final synchronized void join(long millis)
    throws InterruptedException {
    //获得系统当前的时间戳
        long base = System.currentTimeMillis();
        //定义当前时间戳为0
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
         //如果传入的等待时间为0
        if (millis == 0) {
        //如果线程是存活的就一直等待,调用wait(0)
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        join(millis);
    }
      public final void join() throws InterruptedException {
        join(0);
    }

从源码可以看出,join的底层就是使用wait机制实现的。

4. 保护性暂停模式的扩展

途中Futures就好比居民楼的一层信箱(每个信箱都有自己的编号),左侧的t0,t2,t4就好比等待邮件的居民(等待结果的线程),右侧t1,t3,t5就好比邮递员。如果需要在多个类之间使用GuardedObject对象,作为参数传递不是很方便,因此设计一个用来解耦的中间类,这样不仅仅能够解藕结果等待者和结果生产者,还能支持多个任务的管理。

在这里插入图片描述

改造GuardedObject类

class  GuardedObject{
    private Object response;
    private int id;
    public GuardedObject(){
        
    }
    public GuardedObject(int id){
        this.id=id;
    }
    public int getId(){
        return id;
    }
    //获取结果
    public Object get() {
        synchronized (this){
            while(response==null){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return  response;
        }
    }

    public void complete(Object response){
        synchronized (this){
            this.response=response;
            this.notify();
        }
    }
}

构造解耦类

class Boxes{
     private static Map<Integer,GuardedObject> box=new ConcurrentHashMap<>();
     //产生一个唯一的id
     public static int id=1;

     private static synchronized int increment(){
        return id++;
     }
     public static  GuardedObject getGuardedObject(int id){
         return box.remove(id);
     }

     public static GuardedObject creatGuardedObject(){
         GuardedObject guardedObject=new GuardedObject(increment());
         box.put(guardedObject.getId(),guardedObject);
         return guardedObject;
     }

     public static Set<Integer> getIds(){
         return box.keySet();
     }

}

创造等待线程和生产线程

@Slf4j
class  PostMan extends Thread{
    private int id;
    private String mail_contex;
    //邮递员创建信件
    public PostMan(int id,String mail_contex){
        this.id=id;
        this.mail_contex=mail_contex;
    }
    @Override
    public void run(){
      GuardedObject guardedObject=Boxes.getGuardedObject(id);
      log.debug("送信-{},内容-{}",id,mail_contex);
      guardedObject.complete(mail_contex);
    }
}
class Boxes{
     private static Map<Integer,GuardedObject> box=new Hashtable<>();
     //产生一个唯一的id
     public static int id=1;

     private static synchronized int increment(){
        return id++;
     }
     public static  GuardedObject getGuardedObject(int id){
         return box.remove(id);
     }

     public static GuardedObject creatGuardedObject(){
         GuardedObject guardedObject=new GuardedObject(increment());
         box.put(guardedObject.getId(),guardedObject);
         return guardedObject;
     }

     public static Set<Integer> getIds(){
         return box.keySet();
     }

}

测试

public class jvm {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new Poeple().start();
        }
        Thread.sleep(1000);
        for (Integer id : Boxes.getIds()) {
            new PostMan(id, "内容" + id).start();
        }
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1184156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速教程|如何在 AWS EC2上使用 Walrus 部署 GitLab

Walrus 是一款基于平台工程理念的开源应用管理平台&#xff0c;致力于解决应用交付领域的深切痛点。借助 Walrus 将云原生的能力和最佳实践扩展到非容器化环境&#xff0c;并支持任意应用形态统一编排部署&#xff0c;降低使用基础设施的复杂度&#xff0c;为研发和运维团队提供…

汽车生产RFID智能制造设计解决方案与思路

汽车行业需求 汽车行业正面临着快速变革&#xff0c;传统的汽车制造方式正在向柔性化、数字化、自动化和数据化的智能制造体系转变&#xff0c;在这个变革的背景下&#xff0c;汽车制造企业面临着物流、生产、配送和资产管理等方面的挑战&#xff0c;为了应对这些挑战&#xf…

为什么亚马逊的轻量应用服务器这么受欢迎 | 个人体验 | 优势所在

文章目录 &#x1f33a;前言⭐什么是轻量应用服务器&#x1f6f8;特点 &#x1f384;亚马逊轻量应用服务器体验如何&#x1f339;亚马逊轻量应用服务器的优势 &#x1f33a;前言 作为一为开发者&#xff0c;我们要开发部署一个自己的网站&#xff0c;要选择一个性能好的服务器…

Mercury性能测试模板

xxxxxxxxxx 性能测试报告 2023年11月8日 目 录 1 前言 1 1第一章XXXXXXXX核心业务系统性能测试概述 1 1.1 被测系统定义 1 1.1.1 功能简介 1 1.1.2 性能测试指标 2 1.2 系统结构及流程 2 1.2.1 系统总体结构 2 1.2.2 功能模块描述 3 1.2.3 业务…

简单免费工具帮你恢复Windows中已删除的文件!

​如果你在Windows上丢失了文件&#xff0c;有许多工具可以找到并恢复它们&#xff0c;但WinFR界面版既免费又好用&#xff0c;借助该软件你可以轻松恢复丢失的文件。 Microsoft提供了一款免费的工具&#xff0c;可以帮你找到并恢复因意外删除或磁盘或软件问题导致丢…

Nginx实现tcp代理并实现TLS加密

Nginx源码编译 关于nginx的搭建配置具体参考笔者之前的一篇文章&#xff1a;实时流媒体服务器搭建试验&#xff08;nginxrtmp&#xff09;_如何在线测试流媒体rtmp搭建成功了吗-CSDN博客中的前半部分&#xff1b;唯一变化的是编译参数&#xff08;添加stream模块并添加其对应ss…

竞赛选题 深度学习手势识别 - yolo python opencv cnn 机器视觉

文章目录 0 前言1 课题背景2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存 5 模型训练5.1 修…

java中拼接“

params " " paramName "\"" paramValue "\"";

为什么说数据安全运维难?有好用的数据安全运维平台吗?

随着息技术的快速发展&#xff0c;不少企业在实行数字化转型&#xff0c;同时也面临着越来越多的数据安全运维挑战。不少企业都觉得数据安全运维难&#xff0c;都在找好用的数据安全运维平台。今天我们就来聊聊为什么说数据安全运维难&#xff1f;以及是否有好用的数据安全运维…

指纹浏览器有什么用?盘点指纹浏览器八大应用场景

在网络世界中&#xff0c;浏览器指纹一词早已耳熟能详。比如你用的浏览器类型、设备信息&#xff0c;甚至是你的操作习惯等等这些浏览器指纹信息可以让网站轻松识别出你的身份&#xff0c;把你的信息发送给第三方的广告商&#xff0c;然后匹配你的情况进行广告营销。 即使在清除…

广州小程序开发公司怎么找?

在当今的数字化时代&#xff0c;小程序已经成为了企业拓展业务、提升品牌影响力的重要工具。广州作为国内经济中心之一&#xff0c;拥有众多的企业和商家&#xff0c;因此对于小程序开发的需求也日益增长。那么&#xff0c;如何在广州找到一家专业、可靠的小程序开发公司呢&…

六种最常见的软件供应链攻击

软件供应链攻击已成为当前网络安全领域的热点话题&#xff0c;其攻击方式的多样性和复杂性使得防御变得极为困难。以下我们整理了六种常见软件供应链攻击方法及其典型案例&#xff1a; 软件供应链攻击已成为当前网络安全领域的热点话题&#xff0c;其攻击方式的多样性和复杂性…

TSN协议解读系列 | (3) Qci:说书唱戏劝人方

你是谁&#xff1f;你从哪里来&#xff1f;你到哪里去&#xff1f;这是柳国旅问的最多的三个问题。他总在想&#xff0c;上辈子的自己一定是一个哲学家&#xff0c;不然也不会和这三个问题的关系如此密切。他站的笔挺&#xff0c;耳边是蝉鸣&#xff0c;眼前是蓝天&#xff0c;…

定岗定编设计:企业职能部门定岗定编设计项目成功案例

一、客户背景及现状分析 某大型车辆公司隶属于某央企集团&#xff0c;建于20世纪60年代&#xff0c;是中国高速、重载、专用铁路车辆生产经营的优势企业&#xff0c;轨道车辆制动机研发制造的主导企业&#xff0c;是隶属于国内最大的轨道交通设备制造上市企业的骨干二级公司。公…

JVM虚拟机:垃圾回收器之ParNew(年轻代)

本文重点 在前面的课程中,我们学习了新生代的垃圾回收器PS,本文我们将学习新生代的另一个垃圾回收器ParNew。 工作状态 这个垃圾回收器使用多线程进行垃圾回收,在垃圾回收时,会STW(stop-the-world)暂停其它所有的工作线程直到它的收集结束,如下所示: 配置 -XX:+UserP…

南昌大学漏洞报送证书

获取来源&#xff1a;edusrc&#xff08;教育漏洞报告平台&#xff09; url&#xff1a;https://src.sjtu.edu.cn/ 兑换价格&#xff1a;20金币 获取条件&#xff1a;南昌大学任意中危或以上级别漏洞

Matlab论文插图绘制模板第125期—特征渲染的三维气泡图

在之前的文章中&#xff0c;分享了很多Matlab三维气泡图的绘制模板&#xff1a; 进一步&#xff0c;再来分享一下特征渲染的三维气泡图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下载。有需要的…

编程系统化教程目录,中文编程工具下载

图下图是编程工具界面&#xff0c;其构件板构件非常丰富。想学编程&#xff0c;可以点击最下方卡片—— 软件下载——免费自由版软件下载及教程&#xff0c;了解详细资讯。 编程系统化教程视频课程总目录 链接&#xff0c;点击下方链接进入 https://jywxz.blog.csdn.net/art…

Linux的常见指令(三)

目录 一、管道 | 二、find 三、which 四、grep 五、zip/unzip 六、alias 七、输出重定向与输入重定向 1、echo 2、输出重定向 3、输入重定向 八、tar 九、bc 十、uname -r 十一、热键 一、管道 | 我们首先创建一个下面这样的文件 前面我们知道了使用head和tail分…

springboot调用第三方接口json转换成对象

请求接口是一个比较常见的需求&#xff0c;接口返回一般是一个json类型&#xff0c;需要进行组装成对应的类&#xff0c;例 {"status_code": 200,"message": "success","data": {"cost": 286.6933,"bom_list": […