设计模式之保护性暂停
文章目录
- 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 的独特和基本优势在于它可以通过 𝕏 平台实时了…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
