设计模式之保护性暂停

文章目录

    • 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();//定义当前时间戳为0long now = 0;if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}//如果传入的等待时间为0if (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<>();//产生一个唯一的idpublic 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;}@Overridepublic 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<>();//产生一个唯一的idpublic 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.mzph.cn/news/136546.shtml

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

相关文章

SPASS-交叉表分析

导入数据 修改变量测量类型 分析->描述统计->交叉表 表中显示行、列变量通过卡方检验给出的独立性检验结果。共使用了三种检验方法。上表各种检验方法显著水平sig.都远远小于0.05,所以有理由拒绝实验准备与评价结果是独立的假设&#xff0c;即认为实验准备这个评价指标是…

【Git系列】Github指令搜索

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

深度学习之基于Python+OpenCV(DNN)性别和年龄识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 基于Python和OpenCV的深度学习性别和年龄识别系统是一种利用深度学习模型来自动识别人脸照片中的性别和年龄的技术。…

论文速览 | TRS 2023: 使用合成微多普勒频谱进行城市鸟类和无人机分类

注1:本文系“最新论文速览”系列之一,致力于简洁清晰地介绍、解读最新的顶会/顶刊论文 论文速览 | TRS 2023: Urban Bird-Drone Classification with Synthetic Micro-Doppler Spectrograms 原始论文:D. White, M. Jahangir, C. J. Baker and M. Antoniou, “Urban Bird-Drone…

SAP ABAP基础语法-Excel上传(十)

EXCEL BDS模板上传及赋值 上传模板事务代码&#xff1a;OAER l 功能代码&#xff1a;向EXCEL模板中写入数据示例代码如下 REPORT ZEXCEL_DOI. “doi type pools TYPE-POOLS: soi. *SAP Desktop Office Integration Interfaces DATA: container TYPE REF TO cl_gui_custom_c…

React向组件内部动态传入带内容的结构--props

children props&#xff1a;通过组件标签体传入结构 <A><B>xxx</B> </A> {this.props.children}render props&#xff1a;通过组件标签属性传入结构&#xff0c;一般用render函数属性 <A render{data> <C data{data}></C>}></…

P6入门:项目初始化1-项目详情介绍

前言 使用项目详细信息查看和编辑有关所选项目的详细信息&#xff0c;在项目创建完成后&#xff0c;初始化项目是一项非常重要的工作&#xff0c;涉及需要设置的内容包括项目名&#xff0c;ID,责任人&#xff0c;日历&#xff0c;预算&#xff0c;资金&#xff0c;分类码等等&…

MeterSphere 任意文件读取漏洞(CVE-2023-25814)

MeterSphere 任意文件读取漏洞&#xff08;CVE-2023-25814&#xff09; 免责声明漏洞描述漏洞影响漏洞危害网络测绘Fofa: title"MeterSphere" 漏洞复现1. 构造poc2. 发送数据包3. 查看文件 免责声明 仅用于技术交流,目的是向相关安全人员展示漏洞利用方式,以便更好地…

线性代数(六)| 二次型 标准型转换 正定二次型 正定矩阵

文章目录 1. 二次型化为标准型1.1 正交变换法1.2 配方法 2 . 正定二次型与正定矩阵 1. 二次型化为标准型 和第五章有什么样的联系 首先上一章我们说过对于对称矩阵&#xff0c;一定存在一个正交矩阵Q&#xff0c;使得$Q^{-1}AQB $ B为对角矩阵 那么这一章中&#xff0c;我们…

C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发006:基于redis查找玩家姓名+游戏业务实现总结

文章目录 1 Redis的安装与API的使用1.1 安装目录及环境变量1.2 设置远程客户端连接和守护进程1.3 启动redis1.4 Hiredis API的使用1.5 我的动态库和头文件 2 Redis的使用2.1 初始化时候2.2 结束的时候 3 测试4 Makefile5 游戏业务总结 1 Redis的安装与API的使用 1.1 安装目录及…

VUE页面导出PDF方案

1&#xff0c;技术方案为&#xff1a;html2canvas把页面生成canvas图片&#xff0c;再通过jspdf生成PDF文件&#xff1b; 2&#xff0c;安装依赖&#xff1a; npm i html2canvas -S npm i jspdf -S 3&#xff0c;封装导出pdf方法exportPdf.js: // 页面导出为pdf格式 //titl…

已解决:rm: 无法删除“/opt/module/zookeeper-3.4.10/zkData/zookeeper_server.pid“: 权限不够

解决&#xff1a; ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg Stopping zookeeper ... /opt/module/zookeeper-3.4.10/bin/zkServer.sh: 第 182 行:kill: (4149) - 不允许的操作 rm: 无法删除"/opt/module/zooke…

【技术驿站】分布式基础与常见面试问题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

SQL第三次上机作业

1.查询与王利就读同一专业学生的借书证号和姓名 USE TSGL GO SELECT Lno,Rname FROM Reader WHERE Dept(SELECT DeptFROM ReaderWHERE Rname王利) and Rname ! 王利2.查询比希望出版社出版的所有图书价格都高的图书信息 SELECT * FROM Book WHERE Price>(SELECT MAX(Price…

【经验模态分解】3.EMD模态分解算法设计与准备工作

/*** poject 经验模态分解及其衍生算法的研究及其在语音信号处理中的应用* file EMD模态分解算法设计与准备工作* author jUicE_g2R(qq:3406291309)* * language MATLAB* EDA Base on matlabR2022b* editor Obsidian&#xff08;黑曜石笔记软…

Unity3d C#实现编辑器不运行状态下执行的脚本

第一章方式&#xff1a; 函数前面 [ContextMenu("Play")] &#xff0c;Inspector面板右键调用 第二种方式&#xff1a; OnValidate() &#xff0c;值改变自动执行 using UnityEngine; using System.Linq;public class NightController : MonoBehaviour {pub…

已解决:云原生领域的超时挂载Bug — Kubernetes深度剖析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

17.复制字符串 ,包括\0

#include<stdio.h> #include <cstring>int main(){int len1,len2;char s1[44];char s2[33];scanf("%s",s1);scanf("%s",s2);len1strlen(s1)1;printf("先s1的字符长度为&#xff1a;%d\n",len1) ;strcpy(s1,s2) ;printf("复制字…

CCF ChinaSoft 2023 论坛巡礼 | 云计算标准化论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

03【远程协作开发、TortoiseGit、IDEA绑定Git插件的使用】

上一篇&#xff1a;02【Git分支的使用、Git回退、还原】 下一篇&#xff1a;【已完结】 目录&#xff1a;【Git系列教程-目录大纲】 文章目录 一、远程协作开发1.1 远程仓库简介1.1.1 Github1.1.2 Gitee1.1.3 其他托管平台 1.2 发布远程仓库1.2.1 创建项目1&#xff09; 新…