设计模式——保护性暂停

同步模式之保护性暂停

文章目录

  • 同步模式之保护性暂停
    • 定义
    • 实现
    • 应用
    • 带超时版 GuardedObject
    • 扩展——原理之join
    • 扩展——多任务版 GuardedObject

定义

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

  • 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject
  • 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者)
  • JDK 中,join 的实现、Future 的实现,采用的就是此模式
  • 因为要等待另一方的结果,因此归类到同步模式
    在这里插入图片描述

实现

class GuardedObject {private Object response;private final Object lock = new Object();public Object get() {synchronized (lock) {// 条件不满足则等待while (response == null) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}return response;}}public void complete(Object response) {synchronized (lock) {// 条件满足,通知等待线程this.response = response;lock.notifyAll();}}}

应用

一个线程等待另一个线程的执行结果

public static void main(String[] args) {GuardedObject guardedObject = new GuardedObject();new Thread(() -> {try {// 子线程执行下载
List<String> response = download();log.debug("download complete...");guardedObject.complete(response);} catch (IOException e) {e.printStackTrace();}}).start();}log.debug("waiting...");// 主线程阻塞等待
Object response = guardedObject.get();log.debug("get response: [{}] lines", ((List<String>) response).size());

执行结果

08:42:18.568 [main] c.TestGuardedObject - waiting...08:42:23.312 [Thread-0] c.TestGuardedObject - download complete...08:42:23.312 [main] c.TestGuardedObject - get response: [3] lines

带超时版 GuardedObject

如果要控制超时时间呢

class GuardedObjectV2 {private Object response;private final Object lock = new Object();public Object get(long millis) {synchronized (lock) {// 1) 记录最初时间
long begin = System.currentTimeMillis();// 2) 已经经历的时间
long timePassed = 0;while (response == null) {// 4) 假设 millis 是 1000,结果在 400 时唤醒了,那么还有 600 要等
long waitTime = millis - timePassed;log.debug("waitTime: {}", waitTime);if (waitTime <= 0) {log.debug("break...");break;}try {lock.wait(waitTime);} catch (InterruptedException e) {e.printStackTrace();}// 3) 如果提前被唤醒,这时已经经历的时间假设为 400timePassed = System.currentTimeMillis() - begin;log.debug("timePassed: {}, object is null {}", 
timePassed, response == null);}return response;}}public void complete(Object response) {synchronized (lock) {// 条件满足,通知等待线程
this.response = response;log.debug("notify...");lock.notifyAll();}}}

测试,没有超时

public static void main(String[] args) {GuardedObjectV2 v2 = new GuardedObjectV2();new Thread(() -> {sleep(1);v2.complete(null);sleep(1);v2.complete(Arrays.asList("a", "b", "c"));}).start();Object response = v2.get(2500);if (response != null) {log.debug("get response: [{}] lines", ((List<String>) response).size());} }}
else {log.debug("can't get response");

输出

08:49:39.917 [main] c.GuardedObjectV2 - waitTime: 250008:49:40.917 [Thread-0] c.GuardedObjectV2 - notify...08:49:40.917 [main] c.GuardedObjectV2 - timePassed: 1003, object is null true08:49:40.917 [main] c.GuardedObjectV2 - waitTime: 149708:49:41.918 [Thread-0] c.GuardedObjectV2 - notify...08:49:41.918 [main] c.GuardedObjectV2 - timePassed: 2004, object is null false08:49:41.918 [main] c.TestGuardedObjectV2 - get response: [3] lines

测试,超时

// 等待时间不足
List<String> lines = v2.get(1500);

输出

08:47:54.963 [main] c.GuardedObjectV2 - waitTime: 150008:47:55.963 [Thread-0] c.GuardedObjectV2 - notify...08:47:55.963 [main] c.GuardedObjectV2 - timePassed: 1002, object is null true08:47:55.963 [main] c.GuardedObjectV2 - waitTime: 49808:47:56.461 [main] c.GuardedObjectV2 - timePassed: 1500, object is null true08:47:56.461 [main] c.GuardedObjectV2 - waitTime: 008:47:56.461 [main] c.GuardedObjectV2 - break...08:47:56.461 [main] c.TestGuardedObjectV2 - can't get response08:47:56.963 [Thread-0] c.GuardedObjectV2 - notify...

扩展——原理之join

join的底层就是使用保护性暂停的设计模式

扩展——多任务版 GuardedObject

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

在这里插入图片描述
中间用来解耦的类要维护一个集合,同时为了把多个guardedObject区分开,要加上id。

新增 id 用来标识 Guarded Object

 class GuardedObject {// 标识 Guarded Objectprivate int id;public GuardedObject(int id) {this.id = id;}public int getId() {return id;}// 结果
private Object response;// 获取结果
// timeout 表示要等待多久 2000public Object get(long timeout) {synchronized (this) {// 开始时间 15:00:00long begin = System.currentTimeMillis();// 经历的时间
long passedTime = 0;while (response == null) {// 这一轮循环应该等待的时间
long waitTime = timeout - passedTime;// 经历的时间超过了最大等待时间时,退出循环
if (timeout - passedTime <= 0) {break;}try {this.wait(waitTime); // 虚假唤醒 15:00:01} 
catch (InterruptedException e) {e.printStackTrace();}// 求得经历时间
passedTime = System.currentTimeMillis() - begin; // 15:00:02  1s}return response;}}// 产生结果
public void complete(Object response) {synchronized (this) {// 给结果成员变量赋值
this.response = response;this.notifyAll();}}}

中间解耦类

class Mailboxes {private static Map<Integer, GuardedObject> boxes = new Hashtable<>();private static int id = 1;// 产生唯一 idprivate static synchronized int generateId() {return id++;}public static GuardedObject getGuardedObject(int id) {return boxes.remove(id);}}public static GuardedObject createGuardedObject() {GuardedObject go = new GuardedObject(generateId());boxes.put(go.getId(), go);return go;}public static Set<Integer> getIds() {return boxes.keySet();}

业务相关类

class People extends Thread{@Overridepublic void run() {// 收信
GuardedObject guardedObject = Mailboxes.createGuardedObject();log.debug("开始收信 id:{}", guardedObject.getId());Object mail = guardedObject.get(5000);log.debug("收到信 id:{}, 内容:{}", guardedObject.getId(), mail);}}
 class Postman extends Thread {private int id;private String mail;public Postman(int id, String mail) {this.id = id;this.mail = mail;}}@Overridepublic void run() {GuardedObject guardedObject = Mailboxes.getGuardedObject(id);log.debug("送信 id:{}, 内容:{}", id, mail);guardedObject.complete(mail);}

测试

public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 3; i++) {new People().start();}Sleeper.sleep(1);for (Integer id : Mailboxes.getIds()) {new Postman(id, "内容" + id).start();}}

某次运行结果

10:35:05.689 c.People [Thread-1] - 开始收信 id:310:35:05.689 c.People [Thread-2] - 开始收信 id:110:35:05.689 c.People [Thread-0] - 开始收信 id:210:35:06.688 c.Postman [Thread-4] - 送信 id:2, 内容:内容210:35:06.688 c.Postman [Thread-5] - 送信 id:1, 内容:内容110:35:06.688 c.People [Thread-0] - 收到信 id:2, 内容:内容210:35:06.688 c.People [Thread-2] - 收到信 id:1, 内容:内容110:35:06.688 c.Postman [Thread-3] - 送信 id:3, 内容:内容310:35:06.689 c.People [Thread-1] - 收到信 id:3, 内容:内容3

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

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

相关文章

【Linux】进程的控制①之进程创建与进程退出

目录 ​编辑 一 、进程的创建 1、fork函数 2.函数的返回值 ①return 可以返回两次&#xff0c;使得父子进程读到的id有两个值 ②写实拷贝&#xff0c;使得父子进程读到的值都对自身有意义 a.为什么要写实拷贝&#xff0c;而不是在创建子进程的时候直接就将空间给子进程开辟好&a…

Linux系统安装Redis7(详细版)

Linux系统安装Redis7 一、windows安装redis二、Linux安装Redis下载redis编辑redis7.conf文件启动redis-server服务如何关闭redis服务设置Redis开机自启动 一、windows安装redis Window 下安装 下载地址&#xff1a;https://github.com/dmajkic/redis/downloads 下载到的Redi…

【Qt之·控件·样式表】

系列文章目录 文章目录 前言一、Qt样式表的基础知识1.1 Qt样式表的定义和语法规则1.2 Qt样式表中的选择器和属性1.2.1 盒子模型1.2.2 border 1.3 Qt样式表中的伪类和伪元素 二、编写基本的Qt样式表2.1 在Qt应用程序中引入样式表文件的方式2.2 设置基本的背景色、字体样式等 三、…

MATLAB中功率谱密度计算pwelch函数使用详解

MATLAB中功率谱密度计算pwelch函数使用详解 目录 前言 一、pwelch函数简介 二、pwelch函数参数说明 三、pxx pwelch(x)示例 四、[pxx,f]pwelch(x,window,noverlap,nfft,fs)示例 四、[pxx,f] pwelch(x,window,noverlap,nfft,fs,freqrange,spectrumtype)示例 五、多通道功…

SpringCloud整合Gateway结合Nacos

目录 一、引入依赖 二、开启两个测试项目 2.1 order service ​编辑 2.2 user service 三、gateway项目 3.1 新建一个bootstrap.yml文件 3.2 将我们的的网关配置写道nacos里的配置里 3.3 测试&#xff1a;看能够根据网关路由到两个测试的项目 四、 优化 4.1 将项目打包…

低代码技术在构建质量管理系统中的应用与优势

引言 在当今快节奏的商业环境中&#xff0c;高效的质量管理系统对于组织的成功至关重要。质量管理系统帮助组织确保产品或服务符合客户的期望、符合法规标准&#xff0c;并持续改进以满足不断变化的需求。与此同时&#xff0c;随着技术的不断进步&#xff0c;低代码技术作为一…

Windows系统启动Redis

一、下载windows版本Redis 1.1 选择一个使用的版本 在以下地址中选择一个Windows系统可以使用的版本 https://github.com/microsoftarchive/redis/tags 1.2 下载 1.3 解压到文件夹 二、启动Redis 双击redis-server.exe启动Redis 出现以下界面即启动成功 三、测试是否可以使…

hive-row_number() 和 rank() 和 dense_rank()

row_number() 是无脑排序 rank() 是相同的值排名相同&#xff0c;相同值之后的排名会继续加&#xff0c;是我们正常认知的排名&#xff0c;比如学生成绩。 dense_rank()也是相同的值排名相同&#xff0c;接下来的排名不会加。不会占据排名的坑位。

DB-GPT部署验证

一、DB-GPT简介 DB-GPT是一个开源的数据库领域大模型框架。目的是构建大模型领域的基础设施&#xff0c;通过开发多模型管理、Text2SQL效果优化、RAG框架以及优化、Multi-Agents框架协作等多种技术能力&#xff0c;让围绕数据库构建大模型应用更简单&#xff0c;更方便。 GITHU…

R语言4版本安装mvstats(纯新手)

首先下载mvstats.R文件 下载mvstats.R文件点此链接&#xff1a;https://download.csdn.net/download/m0_62110645/89251535 第一种方法 找到mvstats.R的文件安装位置&#xff08;R语言的工作路径&#xff09; getwd() 将mvstats.R保存到工作路径 在R中输入命令 source(&qu…

分享我的github仓库

这是一个由现代C编写的小型、学习性质的服务器框架&#xff0c;包含压缩&#xff0c;序列化&#xff0c;IO调度&#xff0c;Socket封装&#xff0c;文件配置&#xff0c;日志库等多个完整自研模块&#xff0c;欢迎到我的仓库阅读代码和安装体验&#xff0c;期待任何的建议和反馈…

Themis新篇章:老牌衍生品协议登陆Blast L2,探索全新经济模型

本文将深入分析 Themis 的最新经济模型&#xff0c;探讨其核心概念和机制、优势与创新之处、风险与挑战。 一、引言 随着区块链技术的不断发展&#xff0c;DeFi 衍生品项目逐渐成为市场的焦点。而用户体验的革新&#xff0c;进一步的金融创新&#xff0c;去中心化治理方案的优…

Linux开发板 FTP 服务器移植与搭建

VSFTPD&#xff08;Very Secure FTP Daemon&#xff09;是一个安全、稳定且快速的FTP服务器软件&#xff0c;广泛用于Unix和Linux操作系统。它以其轻量级、高效和易于配置而受到赞誉。VSFTPD不仅支持标准的FTP命令和操作&#xff0c;还提供了额外的安全特性&#xff0c;如匿名F…

Python爬取豆瓣电影Top250数据

任务 爬取豆瓣电影top250中的影片名称、影片海报、年份、地区、类型、评分、评价人数、总体评价&#xff0c;并输出到douban_top250.xlsx文件中 环境 Python 3.8 requests bs4 openpyxl 源码 # 创建一个新的Excel工作簿 workbook openpyxl.Workbook() # 获取默认的工作表…

软件工程全过程性文档(软件全套文档整理)

软件项目相关全套精华资料包获取方式①&#xff1a;进主页。 获取方式②&#xff1a;本文末个人名片直接获取。 在软件开发的全过程中&#xff0c;文档是记录项目进展、决策、设计和测试结果的重要工具。以下是一个简要的软件全过程性文档梳理清单&#xff1a; 需求分析阶段…

“Unite“ > MacOS下很不错的网站转应用App的工具

前言 前不久在浏览mac论坛&#xff0c;无意了解到一款非常好的工具&#xff0c;可以将网站转换为app&#xff0c;考虑到我们现在的主要应用都从本地客户端转成web形式使用&#xff0c;但基于本能的使用习惯&#xff0c;还是希望有个快捷的访问信息&#xff0c;这个应用非常适合…

集成框架 -- OSS

前言 接入oss必须有这两个文档基础 使用STS临时访问凭证访问OSS_对象存储(OSS)-阿里云帮助中心 前端上传跨域 正文 sts前后端通用&#xff0c;开通图示 AliyunSTSAssumeRoleAccess 后端实现代码 public static void main(String[] args) {String regionId "cn-ha…

java-函数式编程-函数对象

定义 什么是合格的函数&#xff1f;无论多少次执行函数&#xff0c;只要输入一样&#xff0c;输出就不会改变 对象方法的简写 其实在类中&#xff0c;我们很多参数中都有一个this&#xff0c;被隐藏传入了 函数也可以作为对象传递&#xff0c;lambda就是很好的例子 函数式接口中…

性能监控之prometheus+grafana搭建

前言 Prometheus和Grafana是两个流行的开源工具&#xff0c;用于监控和可视化系统和应用程序的性能指标。它们通常一起使用&#xff0c;提供了强大的监控和数据可视化功能。 Prometheus Prometheus是一种开源的系统监控和警报工具包。它最初由SoundCloud开发&#xff0c;并于…

[数据结构]———归并排序

具体代码&#xff1a;在gitee仓库&#xff1a;登录 - Gitee.com 目录 ​编辑 1.基本思想&#xff1a; 2. 代码解析 1.分析 2.逻辑图 3.运行结果 1.基本思想&#xff1a; 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分…