设计模式之保护性暂停
文章目录
- 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();}}
}

相关文章:
设计模式之保护性暂停
文章目录 1. 定义2. 实现保护性暂停模式3. Join原理4. 保护性暂停模式的扩展 1. 定义 即Guarded Suspension,用在一个线程等待另一个线程的执行结果。 有一个结果需要从一个线程传递给另一个线程,让他们关联到同一个GuarderObject(这就是保…...
UE5、CesiumForUnreal实现加载GeoJson绘制单面(Polygon)功能(StaticMesh方式)
文章目录 1.实现目标2.实现过程2.1 实现原理2.1.1 数据读取2.1.2 三角剖分2.1.3 创建StaticMesh2.2 应用测试2.2.1 具体代码2.2.2 蓝图应用测试3.参考资料1.实现目标 通过读取本地GeoJson数据,在UE中以StaticMeshComponent的形式绘制出面数据,支持Editor和Runtime环境,GIF动…...
Linux 下以其他用户运行程序
需求: 在root的用户下,设置开启自启,这些服务都要用一个swadmin用户运行。 1、创建需要执行的命令脚本 vim /usr/local/bin/start_services.sh#!/bin/bash runuser -l swadmin -c cd /opt/server/ && ./service.sh start s-app-ser…...
Centos7下安装使用K3S
## K3S简介 K3S官方文档链接 K3s是一个轻量级的、专为容器化应用和Kubernetes集群设计的开源Kubernetes发行版。K3s的目标是提供一个更小、更简单、更易于部署和维护的Kubernetes集群。它是Rancher Labs开发的一个项目,旨在满足边缘计算、IoT设备、开发和测试环境…...
易云维®工厂能耗管理平台系统方案,保证运营质量,推动广东制造企业节能减排
我国《关于完整准确全面贯彻新发展理念推进碳达峰碳中和工作的实施意见》出台,提出了推进碳达峰碳中和工作的总体目标。到2025年,广东具备条件的地区、行业和企业率先实现碳达峰,为全省实现碳达峰、碳中和奠定坚实基础;2030年前实…...
Qwt QwtWheel绘制滚动轮
1.简介 QwtWheel 是一个用于实现滚动轮控件的类库。它基于 Qt 框架,并提供了一些方便的功能来处理滚动轮的事件和绘图。 QwtWheel 类继承自 QWidget类,用于定义滚动轮控件的通用行为。QwtWheel 添加了特定于滚动轮的功能。 QwtWheel 可以用于创建具有滚…...
【C++语法讲解】 | 运算符重构 | 三种运算符的重构方式 |代码演示
文章目录 1,简述2,结构体的定义1,结构体的声明2,结构体的申请 3.1 ,在结构体中重构3.2 在结构体外进行重构 1,简述 通常情况下,我们会创建一些简单的数据结构以应对日常的算法使用,…...
[100天算法】-寻找峰值(day 63)
题目描述 峰值元素是指其值大于左右相邻值的元素。给定一个输入数组 nums,其中 nums[i] ≠ nums[i1],找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。你可以假设 nums[-1] nums[n…...
Go语言开发环境安装,hello world!
1. Go开发包SDK https://golang.google.cn/dl/(国内也可以安装) 根据自己电脑下载对应的安装包,我懒下载了msi安装 然后一路点确定安装Go 2.安装GoLand https://www.jetbrains.com/go/download/#sectionwindows 下载安装包 一路确定安装完…...
记CVE-2022-39227-Python-JWT漏洞
文章目录 前言影响版本漏洞分析Newstar2023 Week5总结 前言 在Asal1n师傅的随口一说之下,说newstar week5出了一道祥云杯一样的CVE,于是自己也是跑去看了一下,确实是自己不知道的一个CVE漏洞,于是就从这道题学习到了python-jwt库…...
软件测试/测试开发丨如何利用ChatGPT自动生成测试用例思维导图
点此获取更多相关资料 简介 思维导图是一种用图形方式表示思维和概念之间关系的工具: 有些公司会使用思维导图编写测试用例,这样做的优点是: 1.可视化和结构化。 2.易于理解,提高效率。 而 ChatGPT 是无法直接生成 xmind 格式…...
【编程语言发展史】Unity开发语言的历史发展
Unity开发前期版本时,使用的是一种名为UnityScript的类似JavaScript的语言。然而,随着时间的推移,开发者社区大多数人都倾向于使用C#进行开发,Unity决定将重点放在C#上,因为C#具有更强大的生态系统、更好的性能和更广泛…...
springboot http添加请求头 添加请求证书
首先明确两个事情:请求对象,连接对象 我们知道你要是想发起一个请求,需要指定两个环节内容,一个是请求内容对象(request),一个是连接内容对象(httpClient) 它们两个的作用我们在下面会看到 简要分析源码 1.先说一下…...
【Qt之数据库操作】
使用Qt实现SQLite数据库操作可以分为以下几个步骤: 添加SQLite头文件和库文件: 在Qt项目中,需要在.pro文件中添加以下内容: QT sql打开/创建数据库: 可以使用QSqlDatabase类中的静态函数addDatabase()来添加数据库…...
数据结构(c语言版) 队列
链队列 要求:实现链队列的创建、初始化、入队、出队 (先进先出) 代码 // // Created by My.cy on 2023/10/19. // //链队列 创建、初始化、入队、出队 先进先出#include <stdio.h> #include <malloc.h>//定义结构体 struct…...
kimera论文阅读
文章目录 功能构成:Kimera线程A. Kimera-VIO:B. Kimera-RPGO:C. Kimera-Mesher:D. Kimera-Semantics:E.调试工具 功能构成: Kimera包括四个关键模块: Kimera-VIO的核心是基于gtsam的VIO方法[45],使用IMUpreintegration和无结构视觉因子[27]…...
golang gorm通过泛型实现通用单表增删改
golang gorm通过泛型实现通用单表增删改 无废话,直接上代码 想实现通用,首先得实现查询的通用,可以用传递map实现 func Where(where map[string]interface{}) func(db *gorm.DB) *gorm.DB {return func(db *gorm.DB) *gorm.DB {dbTmp : db…...
十、K8S之ConfigMap
ConfigMap 一、概念 在K8S中,ConfigMap是一种用于存储配置数据的API对象,一般用于存储Pod中应用所需的一些配置信息,或者环境变量。将配置于 Pod 分开,避免应为修改配置导致还需要重新构建 镜像与容器。 二、创建 可以使用 ku…...
python飞书群机器人通过webhook发送消息
python飞书群机器人通过webhook发送消息 import json import loggingimport requestslogger logging.getLogger(__name__) logging.basicConfig(levellogging.DEBUG)class FeishuTalk:"""飞书群机器人通过webhook发送消息"""def __init__(self…...
埃隆·马斯克的 AI 聊天机器人 Grok 已经上线
昨天,埃隆马斯克 (Elon Musk) 通过他的公司 xAI 推出了一款名为 Grok 的新型人工智能聊天机器人。这款新的聊天机器人将通过 Twitter 更新实时获取世界知识,使其成为最新的对话 AI 系统。 Grok 的独特和基本优势在于它可以通过 𝕏 平台实时了…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
