【Java】设计模式之保护性暂停

设计模式之保护性暂停

Guarded Suspension,这个设计模式,主要用在一个线程等待另一个线程的执行结果(发请求等待响应)

  • 有一个结果需要从一个线程传递到另一个线程,传递只进行一次,用设计模式保护性暂停。

  • 如果有结果不断从一个线程到另一个线程那么可以使用另一个设计模式消息队列(之后的知识)

  • JDK 中, join 的实现、 Future 的实现,采用的就是此模式

  • 因为要等待另一方的结果,因此归类到同步模式

想要让一个线程等待另一个线程的执行结果,可以让这两个线程都关联上同一个 Guarded 0bject保护对象,让对象的管程的waitset来充当通知的桥梁,使用对象的wait()/notify()方法来进行通知。

结果如何从线程2传到线程1?其实保护对象由开发者创建,它的属性就是response。线程1对该对象加锁并执行wait()方法,线程1首先执行陷入阻塞。线程2也对保护对象加锁,当它执行完毕之后,将结果记录在保护对象的response之中然后执行notifyAll()方法唤醒线程1。线程1被唤醒,它就可以从保护对象的response属性中拿到线程2处理的结果。


改进:

如果要多个类之间进行通信,使用保护对象不是很方便。 因此设计一个用来解耦的中间类,这样不仅能够解耦【结果等待者】和【结果生产者】,还能够同时支持多个任务的管理。

注意:在这种情况下,结果等待者和结果生产者还是一一对应的。如果结果等待者和结果生产者是多对多的关系,要用到另一种设计模式——生产者/消费者。

在这里插入图片描述

需要创建一个保护对象的管理器来管理多个保护对象。

package org.example;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Hashtable;
import java.util.Map;/*** @author xcy*/public class Main {static Logger logger= LoggerFactory.getLogger("test");public static void main(String[] args) throws InterruptedException {//结果等待者//这个for循环创建了5个保护对象,创建对象的方法确实是原子性的,但是这5个对象的保护对象不会和线程序号一致//因为5个线程并不是循环new出一个立刻就执行一个,线程的启动会有延迟//比如说线程1、2、3、4、5,并不是按照12345的顺序启动,会随机启动,所以最后线程名和创建出保护对象名称并不一致//如果想要让保护对象的序号与线程一致,要根据当前线程的序号来创建保护对象,而不是循环计数for (int i = 0; i < 5; i++) {int finalI=i;new Thread(() -> {GuardedObject guardedObject = GuardedObjectManager.createGuardedObject();logger.debug("开始等待结果,线程的保护对象为:"+guardedObject.getId());guardedObject.waitResult();logger.debug("等到结果:" + guardedObject.getResponse());},"t"+finalI).start();}Thread.sleep(1000);//结果生产者for (int i = 5; i < 10; i++) {int finalI = i;new Thread(() -> {GuardedObject guardObject = GuardedObjectManager.getGuardObject(finalI - 5);System.out.println(Thread.currentThread()+"获得保护对象:"+guardObject);guardObject.complete(finalI);},"t"+finalI).start();}}
}/*** 保护对象,用于两个线程之间的通信*/
class GuardedObject {private Integer id;private Object response;public GuardedObject(Integer id) {this.id = id;}/*** 拥有该对象锁的线程释放对象锁,进入等待队列*/public synchronized Object waitResult() {while (response == null) {try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}return this.response;}/*** 唤醒该对象等待队列中的线程*/public synchronized void complete(Object response) {System.out.println("线程"+Thread.currentThread()+"返回结果"+response);this.response = response;this.notifyAll();}public Integer getId() {return id;}public Object getResponse() {return response;}@Overridepublic String toString() {return "GuardedObject{" +"id=" + id +'}';}
}/*** 用来管理GuardedObject*/
class GuardedObjectManager {private static int id;/*** 由于hashmap是线程不安全的,所以用hashtable保证put和get的原子性*/public static Map<Integer, GuardedObject> map = new Hashtable<>();public synchronized static GuardedObject createGuardedObject() {System.out.println(Thread.currentThread()+":"+id);GuardedObject guardedObject = new GuardedObject(id);map.put(id, guardedObject);id++;System.out.println(Thread.currentThread()+":"+id);return guardedObject;}public static GuardedObject getGuardObject(int id) {return map.get(id);}
}

结果:

在这里插入图片描述

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

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

相关文章

c语言的一些题(2024_1_7)

变种水仙花数 #include <stdio.h>int main() {int a 10000;for (; a < 100000; a){if ((a / 10000) * (a % 10000) (a / 1000) * (a % 1000) (a / 100) * (a % 100) (a / 10) * (a % 10) a)printf("%d ", a);}return 0; } //变种水仙花数 - Lily Num…

JavaScript异常处理实战

前言 之前在对公司的前端代码脚本错误进行排查&#xff0c;试图降低 JS Error 的错误量&#xff0c;结合自己之前的经验对这方面内容进行了实践并总结&#xff0c;下面就此谈谈我对前端代码异常监控的一些见解。 本文大致围绕下面几点展开讨论&#xff1a; JS 处理异常的方式…

【嵌入式】Makefile 学习笔记记录 | 嵌入式Linux

文章目录 前言一、Makefile的引入——最简单的gcc编译过程二、Makefile的规则三、Makefile的语法3.1、通配符3.2、假想目标 .phony3.3、即时变量 延时变量 四、Makefile的函数4.1、foreach4.2、filter4.3、wildcard4.4、patsubst 五、Makefile升级5.1、包含头文件在内的依赖关系…

二叉树算法题(一)

根据二叉树创建字符串 根据二叉树创建字符串 给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号和整数组成的字符串&#xff0c;返回构造出的字符串。 空节点使用一对空括号对 "()" 表示&#xff0c;转化后需要省…

【Docker基础一】Docker安装Elasticsearch,Kibana,IK分词器

安装elasticsearch 下载镜像 查看版本&#xff1a;Elasticsearch Guide [8.11] | Elastic # 下载镜像 docker pull elasticsearch:7.17.16 # 查看镜像是否下载成功 docker images创建网络 因为需要部署kibana容器&#xff0c;要让es和kibana容器互联 # 创建一个网络&…

超维空间M1无人机使用说明书——01、ROS机载电脑使用说明——远程连接

引言&#xff1a;远程连接通常采用两种方式&#xff0c;一种是通过可视化软件&#xff0c;如VNC、Nomachine等&#xff0c;另外一种是使用SSH。各有优缺点&#xff0c;两种远程登录方式的优缺点做一个简单的对比&#xff1a; 1、SSH优缺点 优点:1、消耗网络资源 2、运行稳定 …

vue结合Cesium加载gltf模型

Cesium支持什么格式&#xff1f; Cesium支持的格式包括&#xff1a;3D模型格式&#xff08;如COLLADA、gITF、OBJ&#xff09;、影像格式&#xff08;如JPEG、PNG、GeoTIFF&#xff09;、地形格式&#xff08;如STL、Heightmap&#xff09;、矢量数据格式&#xff08;如GeoJSON…

如何实现公网访问GeoServe Web管理界面共享空间地理信息【内网穿透】

文章目录 前言1.安装GeoServer2. windows 安装 cpolar3. 创建公网访问地址4. 公网访问Geo Servcer服务5. 固定公网HTTP地址 前言 GeoServer是OGC Web服务器规范的J2EE实现&#xff0c;利用GeoServer可以方便地发布地图数据&#xff0c;允许用户对要素数据进行更新、删除、插入…

遗传算法(GA)、模拟退火算法(SAA)、蚁群算法(ACO)、粒子群算法(PSO)优缺点汇总

遗传算法 优点&#xff1a; 与问题领域无关且快速随机的搜索能力&#xff0c;不会陷入局部最优解&#xff1b;搜索从群体出发&#xff0c;具有潜在的并行性&#xff0c;提高运行速度&#xff0c;鲁棒性高&#xff1b;搜索使用评价函数启发&#xff0c;过程简单&#xff1b;使…

服务容错-熔断策略之断路器hystrix-go

文章目录 概要一、服务熔断二、断路器模式三、hystrix-go3.1、使用3.2、源码 四、参考 概要 微服务先行者Martin Fowler与James Lewis在文章microservices中指出了微服务的九大特征&#xff0c;其中一个便是容错性设计(Design for failure)。正如文章中提到的&#xff0c;微服…

【LMM 013】ImageBind: One Embedding Space To Bind Them All

论文标题&#xff1a;ImageBind: One Embedding Space To Bind Them All 论文作者&#xff1a;Rohit Girdhar, Alaaeldin El-Nouby, Zhuang Liu, Mannat Singh Kalyan, Vasudev Alwala, Armand Joulin, Ishan Misra∗ 作者单位&#xff1a;FAIR, Meta AI 论文原文&#xff1a;h…

SpringSecurity集成JWT实现后端认证授权保姆级教程-数据准备篇

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525;网站…