设计模式之保护性暂停

文章目录

    • 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();
        }
    }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Chromebook文件夹应用新功能

种种迹象表明 Google 旗下的 Chromebooks 近期要有大动作了。根据 Google 团队成员透露&#xff0c;公司计划在 Chrome OS 的资源管理器中新增“Recents”&#xff08;最近使用&#xff09;文件&#xff0c;以便于用户更快找到所需要的文件。 种种迹象表明 Google 旗下的 Chro…

Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较

Flutter vs 前端 杂谈 SliverAppBar的弹性背景的显隐效果使用HtmlJS怎么实现 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550…

有电闭锁继电器 YDB-100 100V 辅助电源DC110V JOSEF约瑟 板后安装

YDB-100有电闭锁继电器 1 应用 本继电器用于发电厂和变电站内&#xff0c;用作高压母线合接地刀闸的闭锁元件&#xff0c;以防止高压母线带电时合接地刀闸。 2 主要性能 2 1采用进口集成电路和元器件构成。具有原理先进、性能稳定、可靠性高、动作值精度高、离散值小、整定范围…

文件分片上传设计

shigen日更文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 现在是接近凌晨了&#xff0c;突然有伙伴给我提到了文件分片上传的事情&#xff0c;我一想&#xff0c;这个我熟…

【全志H616 使用标准库 完成自制串口库(分文件实现) orangepi zero2(开源)】.md updata: 23/11/07

文章目录 H616 把玩注意&#xff1a;Linux内核版本5.16 及以上&#xff0c;需手动配置i2c-3 uart5驱动配置示例 分文件编译时需将每个文件一同编译 &#xff08;空格隔开&#xff09;例&#xff1a; ggc a.c b.c b.h -lpthread -lxxx..; 常用命令查看驱动文件查看内核检测信息/…

美妆行业如何通过自媒体提升品牌曝光

自媒体的出现使美妆行业的推广方式产生了变化&#xff0c;自媒体平台的用户年轻化、用户基数大、消费力较强&#xff0c;能够接受新鲜事物&#xff0c;为美妆品牌带来广阔的市场和消费人群。 因此自媒体平台的内容运营十分重要&#xff0c;今天媒介盒子就来和大家聊聊&#xf…

npm install:sill idealTree buildDeps

执行npm install&#xff0c;卡在 sill idealTree buildDeps PS D:\workspace-groovy\attendance-india-web> npm install -g cnpm --registryhttps://registry.npm.taobao.org [..................] / idealTree:node_global: sill idealTree buildDeps[.................…

基于厨师算法的无人机航迹规划-附代码

基于厨师算法的无人机航迹规划 文章目录 基于厨师算法的无人机航迹规划1.厨师搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用厨师算法来优化无人机航迹规划。 1.厨师搜索算法 …

NSSCTF web刷题记录4

文章目录 [NSSRound#4 SWPU]1zweb(revenge)[强网杯 2019]高明的黑客[BJDCTF 2020]Cookie is so subtle![MoeCTF 2021]fake game[第五空间 2021]PNG图片转换器[ASIS 2019]Unicorn shop[justCTF 2020]gofs[UUCTF 2022 新生赛]phonecode[b01lers 2020]Life On Mars[HZNUCTF 2023 f…

Python 中 Selenium 的 getAttribute() 函数

Selenium 的 Python 模块旨在提供自动化测试过程。 Selenium Python 绑定包括一个用于编写 Selenium WebDriver 功能/验收测试的简单 API。 拥有移动能力并没有多大好处。 我们想要与页面交互&#xff0c;或者更准确地说&#xff0c;与组成页面的 HTML 片段交互。 本文将解释…

基于springboot和vue的校园二手物品交易管理系统

博主24h在线&#xff0c;想要源码文档部署视频直接私聊&#xff0c;全网最低价&#xff0c;9.9拿走&#xff01; 基于VUE的校园二手物品交易管理系统8 1、项目介绍 基于VUE的校园二手物品交易管理系统8拥有两种角色 管理员&#xff1a;闲置物品管理、订单管理、用户管理 用户…

【bug-maven】(一)java: 错误: 不支持发行版本 5 (二):java: 错误: 无效的源发行版:15

【bug-maven】&#xff08;一&#xff09;java: 错误: 不支持发行版本 5 &#xff08;二&#xff09;&#xff1a;java: 错误: 无效的源发行版&#xff1a;15 &#xff08;一&#xff09;java: 错误: 不支持发行版本 5 报错截图&#xff1a; 出错原因&#xff1a; 打开Projec…

SAP-MM-查找采购订单的创建和修改日期

在采购订单页面可以查看采购订单的修改和创建&#xff0c;但是有些内容不能完成看到 例如这个订单显示是用户唐创建&#xff0c;但是他不记得是什么时候创建的&#xff0c;怎么创建的&#xff1f; 点击菜单-环境-表头更改、项目更改&#xff0c;可以查看更改内容 通过这个表可…

C语言——数组

一&#xff0c;数组的概念和特点 数组是存放两个或两个以上相邻储存单元的集合&#xff0c;每个储存单元中存放相同数据类型的数据&#xff0c;而这样的单元也被称为数组元素。 我们将这句话进行拆分&#xff0c;不难发现数组的特点有&#xff1a; 1&#xff0c;数组是存放多…

java计算机毕业设计SpringBoot在线答疑系统

项目介绍 本文从学生的功能要求出发&#xff0c;建立了在线答疑系统&#xff0c;系统中的功能模块主要是实现管理员权限&#xff1b;首页、个人中心、学生管理、教师管理、问题发布管理、疑难解答管理。教师权限&#xff1a;首页、个人中心、疑难解答管理、试卷管理、试题管理…

TCP协议

TCP 1. 格式2. TCP原理2.1 确认应答(安全机制)2.2 超时重传(安全机制)2.3 连接管理机制(安全机制)2.3.1 三次握手2.3.2 四次挥手 2.4 滑动窗口(效率机制) 2.5 流量控制(效率机制) 1. 格式 源/目的端口号&#xff1a;表示数据是从哪个进程来&#xff0c;到哪个进程去&#xff1b…

机器学习——回归

目录 一、线性回归 1、回归的概念&#xff08;Regression、Prediction&#xff09; 2、符号约定 3、算法流程 4、最小二乘法&#xff08;LSM&#xff09; 二、梯度下降 梯度下降的三种形式 1、批量梯度下降&#xff08;Batch Gradient Descent,BGD&#xff09;&#xff…

基于SpringBoot+Vue的点餐管理系统

基于springbootvue的点餐平台网站系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 菜品详情 个人中心 订单 管理员界面 菜品管理 摘要 点餐管理系统是一种用…

一个使用uniapp+vue3+ts+pinia+uview-plus开发小程序的基础模板

uniappuviewPlusvue3tspiniavite 开发基础模板 使用 uniapp vue3 ts pinia vite 开发基础模板&#xff0c;拿来即可使用&#xff0c;不要删除 yarn.lock 文件&#xff0c;否则会启动报错&#xff0c;这个可能和 pinia 的版本有关&#xff0c;所以不要随意修改。 拉取代码…

Java根据一个List内Object的两个字段去重

背景 在Java开发过程中&#xff0c;我们经常会遇到需要对List进行去重的需求。 其中常见的情况是&#xff0c;将数组去重&#xff0c;或者将对象依据某个字段去重。这两种方式均可用set属性进行处理。 今天讨论&#xff0c;有一个List&#xff0c;且其中的元素是自定义的对象&…