【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;
    }

    @Override
    public 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);
    }
}

结果:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

46 WAF绕过-信息收集之反爬虫延时代理池技术

目录 简要本章具体内容和安排缘由简要本课具体内容和讲课思路简要本课简要知识点和具体说明演示案例:Safedog-默认拦截机制分析绕过-未开CCSafedog-默认拦截机制分析绕过-开启CC总结&#xff1a; Aliyun_os-默认拦截机制分析绕过-简要界面BT(防火墙插件)-默认拦截机制分析绕过-…

小米汽车的占用网络是什么

大家好啊&#xff0c;我是董董灿。 昨天小米汽车开了发布会&#xff0c;一下子喜提十几个热搜。 就在人们纷纷猜测&#xff0c;小米汽车的定价会不会延续小米极致性价比风格时。 雷总的一句"电池成本都不下于十几万"&#xff0c;瞬间把人们对于小米汽车定价的幻想拉…

CMake入门教程【核心篇】静态库 (.a, .lib)

😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 概述创建静态库添加静态库到你的项目完整代码示例实战使用技巧与注意事项总结与分析概述 静态库在C++开发中扮演着重要的角色。它们通常以.a(在Unix-like系统

新手练习项目 4:简易2048游戏的实现(C++)

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#xff09; 目录 一、效果图二、代码&#xff08;带注释&#xff09;三、说明 一、效果图 二、代码&#xff08;带…

MYSQL篇--索引高频面试题

mysql索引 1什么是索引&#xff1f; 索引说白了就是一种数据结构&#xff0c;可以协助快速查询数据&#xff0c;以及更新数据库表中的数据&#xff0c;更通俗的来说索引其实就是目录&#xff0c;通过对数据建立索引形成目录&#xff0c;便于去查询数据&#xff0c;而mysql索引…

静态网页设计——旅游景点介绍(HTML+CSS+JavaScript)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a; https://www.bilibili.com/video/BV1f64y1N7uH/?vd_source5f425e0074a7f92921f53ab87712357b 使用技术&#xff1a;HTMLCSSJS&#xff08;…

虚拟机VMware安装Linux

关于安装&#xff0c;安装版本是CentOS 7&#xff0c;选择最小安装即可 第一步&#xff1a;选择创建新的虚拟机 第二步&#xff1a;默认典型&#xff0c;点击下一步 第三步&#xff1a;选择稍后安装操作系统 第四步&#xff1a;选择Linux和版本 第五步&#xff1a;输入虚拟机名…

初识Kafka

1.初识kafka 官网&#xff1a;Apache Kafka Apache Kafka是一个分布式流处理平台&#xff0c;最初由LinkedIn开发并于2011年开源。它主要用于解决大规模数据的实时流式处理和数据管道问题。 Kafka是一个分布式的发布-订阅消息系统&#xff0c;可以快速地处理高吞吐量的…

杨中科 ASP.NET Core前后端分离开发

一、 前后端分离 1、传统MVC开发模式: 前后端的代码被放到同一个项目中&#xff0c;前端人员负责编写页面的模板&#xff0c;而后端开发人员负责编写控制器和模型的代码并且“套模板”。 缺点: 互相依赖&#xff0c;耦合性强&#xff0c;责任划分不清。 2、主流的“前后端分离…

西门子WinCC的C脚本——对象的事件任务

1、 全局脚本编辑器&#xff1b; 2、 对象的属性任务&#xff1b; 3、 对象的事件任务。 本文探讨一下用C脚本来实现对象的事件任务。 一、例程说明引文&#xff1a;博途工控人平时在哪里技术交流博途工控人社群 如图1所示&#xff0c;为本例程的运行画面。本例程实现以下…

【MATLAB第89期】基于MATLAB的差分自回归滑动平均模型ARIMA时间序列预测模型含预测未来

【MATLAB第89期】基于MATLAB的差分自回归滑动平均模型ARIMA时间序列预测模型含预测未来 往期文章 【MATLAB第82期】基于MATLAB的季节性差分自回归滑动平均模型SARIMA时间序列预测模型含预测未来 一、模型介绍 1、模型简介 差分自回归移动平均模型&#xff08;Autoregressiv…

外包做了1个月,技术退步一大半了。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;20年通过校招进入深圳某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

【mysql】—— 事务

目录 &#xff08;一&#xff09;前言 &#xff08;二&#xff09;事务的理解 1、为什么会出现事务 2、什么是事务&#xff1f; 3、事务的版本支持 4、事务提交方式 &#xff08;三&#xff09;事务常见操作方式 1、正常演示 - 证明事务的开始与回滚 2、非正常演示…

CSAPP cache lab - Optimizing Matrix Transpose

CSAPP cache lab part B 矩阵转置 矩阵转置是一种操作&#xff0c;它将矩阵的行和列互换位置&#xff0c;即将原始矩阵的行变为转置矩阵的列&#xff0c;将原始矩阵的列变为转置矩阵的行。转置操作可以通过改变矩阵的布局来方便地进行某些计算和分析。 假设有一个mn的矩阵A&…

Qt读取文件对比:每次获取自定义的长度和使用系统的API,耗时对比

0. 前言 在编程过程中&#xff0c;经常遇到文件读写操作&#xff0c;太频繁了。每次也都写的不一样。 突发奇想&#xff0c;想测试下几种不同的读取文件的效率。 测试以下三种方式读取文件效率&#xff1a; 自定义读取文件耗时使用QFile类API读取文件耗时使用QTextStream类AP…

【BIAI】Lecture 5 - Auditory system

Lecture 5 - Auditory system 专业术语 auditory system 听觉系统 pinna 耳廓 auditory canal 耳道 tympanic membrane 鼓膜 cochlea 耳蜗 ossicles 听骨 auditory-vestibular nerve 前庭神经 oval window 椭圆窗 attenuation reflex 衰减反射 tensor tympani muscle 鼓膜张肌…

那些年听烂了的名词之“高可用“

那些年听烂了的名词之"高可用" 引言什么是可用性 ?哪些风险会影响系统的可用性 &#xff1f;如何应对这些风险&#xff0c;从而确保系统的可用性 &#xff1f;Phase: 设计做好容灾和多活处理做好容错设计做好资源隔离做好扩展性设计做好数据一致性处理 Phase: 预防做…

适配器Adapters

1.适配器作用 主要是对底层的东西进行改造 2.适配器种类&#xff1a;容器适配器&#xff0c;迭代器适配器&#xff0c;仿函数适配器 2.1容器适配器&#xff1a; stack&#xff0c;queue他们两的底层结构都为deque&#xff0c;deque有好多功能&#xff0c;而stack&#x…

如何将支持标准可观测性协议的中间件快速接入观测

前言 作为一名云原生工程师&#xff0c;如何将支持标准可观测性协议的中间件快速接入观测云呢&#xff1f;答案是只需要三步。 首先&#xff0c;需要确定您要观测的中间件类型。支持标准可观测性协议中间件可通过观测云的 DataKit 采集到中间件的关键指标。有些中间件自带可观…

文件系统与日志分析

一&#xff0c;文件系统 &#xff08;一&#xff09;inode 和block概述 1&#xff0c;文件数据包括元信息与实际数据 2&#xff0c;文件存储在硬盘上&#xff0c;硬盘最小存储单位是“扇区”&#xff0c;每个扇区存储512字节 3&#xff0c;block (块) 连续的八个扇区组成一…