保护性暂停设计模式

news2024/9/23 9:30:36

目录

保护性暂停设计模式

获取结果

产生结果

总代码实现

测试

增加超时效果的Guarded suspension

get(long timeout)

测试


保护性暂停设计模式

Guarded Suspension 即 保护性暂停; 是一种等待唤醒机制的一种规范 ,也可以理解为使用中设计模式,Java的API很多都按照保护性暂停这种设计模式来的,比如 join,future.

保护性暂停设计模式(Guarded Suspension) ,一般适用于 一个线程等待另外一个线程的执行结果,两个线程一一对应,可以划分为同步的设计模式.

如果你需要一个结果要源源不断的从一个线程到另外一个线程,那就需要使用生产者消费者模式->即消息队列.

保护性暂停设计模式 也是使用到wait和notify这种等待唤醒机制实现的,接下来我给一下它的代码实现:

获取结果

//获取结果
public Object get(){
    synchronized (this){
        while(response==null){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return response;
    }
}

还是按照wait和notify使用来实现, 如果一直没有给response赋值,它就一直等着,如果另外一个线程给response赋值,就立即返回这个结果.

产生结果

//传入/产生 结果
public void complete(Object response){
    synchronized (this) {
        this.response = response;
        this.notifyAll();
    }
}

等到一个线程传入结果即为response赋值,那么就立即给response赋值,然后通知正在等待的线程,唤醒他,让其返回结果.

总代码实现

我们利用GuardedObject来封装这两个方法,关联同一个GuardedObject

/**
 * Description:  保护性暂停模式
 */
public 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.notifyAll();
        }
    }
}

测试

@Slf4j(topic = "c.Main")
public class Main {
    public static void main(String[] args) {
        GuardedObject guardedObject = new GuardedObject();
        //A线程等待B线程的结果
        new Thread(()->{
            List<String> list = (List<String>) guardedObject.get();
            log.debug("得到结果为");
            System.out.println(list);
        },"A").start();

        new Thread(()->{
            try {
                List<String> list = DownLoader.downLoad();
                guardedObject.complete(list);
            } catch (IOException e) {
                e.printStackTrace();
            }
        },"B").start();
    }
}
public class DownLoader {
    public static List<String> downLoad() throws IOException {
        //下载百度首页
        HttpURLConnection connection = (HttpURLConnection) new URL("https://www.baidu.com/").openConnection();
        List<String> lines = new ArrayList<>();
        try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while((line= bufferedReader.readLine()) != null) {
                lines.add(line);
            }
        }
        return lines;
    }
}

写了一个测试类,用来对保护性暂停设计模式进行测试.一个线程A用来接收下载结果,另外一个线程B执行完下载(DownLoader类用于下载百度首页)之后,将下载结果传入,线程A就可以获取到结果然后进行结果的打印.

增加超时效果的Guarded suspension

主要在get()方法上增加超时效果,获取结果的时候,不需要一直等了,可以选择性的等几秒,如果等不到就不等了.

get(long timeout)

为了更好地理解,我先一步一步的改代码,最终形成最终版本

如果想要等待timeout时间,就是等待足够timeout,不能多也不能少.必须整好.

一个问题直接加上Timeout行不行

private Object response;
//获取结果
public Object get(long timeout){
    synchronized (this){
        while(response==null){
            try {
                this.wait(timeout);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return response;
    }
}

答案是不行的,就算等完2s之后还要再次进入while循环,条件还是不成立,又要等待2s,这就相当于每2s等待一次,也就相当于一直等待

所以我们要琢磨一下:

首先最开始刚获取结果的时候就加一个开始时间-->用于记录刚要获取结果的时间,然后等待往后推2s.

long begin = System.currentTimeMillis();//记录刚开始获取结果的时间->刚获取到锁

还必须要一个passTime 表示经历的时间

long passTime = 0;//表示经历的时间,刚开始为0ms

那怎么记录passTime呢 ?

我们需要每轮等待一次之后进行获取->用当时的时间-开始的时间就是

passTime = System.currentTimeMillis() - begin;

当passTime>=timeout 就代表等到了足够时间还没有结果,就不等了立即 break,退出循环不等了.

if(passTime>=timeout){
    break;
}

现在就差wait部分的时间没有填写.

  • 填timeout行不行?

答案是不行的,还要考虑虚假唤醒的情况就比如它在00:00s开始获取结果,timeout=2s,在00:01s时候被唤醒,求得经历时间为1s,再次循环之后passTime>=timeout不成立,然后就会接着在等timeout(2s),但是按理说我们再等待1s就可以了,这样的话你就多等了.

我们等待timeout-passTime就是正确的,这才是一轮需要等待的时间;

于是可以写如下代码:

//获取结果
public Object get(long timeout){
    synchronized (this){
        long begin = System.currentTimeMillis();
        long passTime = 0;
        while(response==null){
            if(passTime>=timeout){
                break;
            }
            try {
                this.wait(timeout-passTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            passTime = System.currentTimeMillis() - begin;
        }
        return response;
    }
}

接着再精简一下给出整体代码:

public class GuardedObject {
    private Object response;
    //获取结果
    public Object get(long timeout){
        synchronized (this){
            long begin = System.currentTimeMillis();
            long passTime = 0;
            while(response==null){
                //应该等待的时间
                long waitTime =  timeout - passTime;
                if(waitTime<=0){
                    break;
                }
                try {
                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passTime = System.currentTimeMillis() - begin;
            }
            return response;
        }
    }
    //传入/产生 结果
    public void complete(Object response){
        synchronized (this) {
            this.response = response;
            this.notifyAll();
        }
    }
}

测试

测试提前传入结果:

测试超时传入结果:

测试虚假唤醒的情况

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【免费开放源码】审批类小程序项目实战(活动审批端)

第一节&#xff1a;什么构成了微信小程序、创建一个自己的小程序 第二节&#xff1a;微信开发者工具使用教程 第三节&#xff1a;深入了解并掌握小程序核心组件 第四节&#xff1a;初始化云函数和数据库 第五节&#xff1a;云数据库的增删改查 第六节&#xff1a;项目大纲以及制…

系分 - 面向对象的方法【概念】

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 系分 - &#xff08;概念&#xff09;面向对象的方法 面向对象的方法&#xff08;OO&#xff0c;Object-Oriented&#xff09;是一种基于对象模型的程序设计方法&#xff0c;包括面向对象的分析&#xff08;OOA&a…

【iOS】内存管理

文章目录前言理解引用计数引用计数原理属性存取方法中的内存管理自动释放池保留环以ARC简化引用计数使用ARC时必须遵守的命名规则变量的内存管理语义ARC如何清理实例变量覆写内存管理的方法在dealloc方法中只释放应用并解除监听前言 内存管理&#xff1a; 在Objective-C这样的…

Windows平台下的内存泄漏检测

Windows平台下的内存泄漏检测一、使用_CrtDumpMemoryLeaks定位内存泄露添加对应的头文件转储内存泄漏信息程序任意点退出指定调试信息输出二、定位具体内存泄露位置内存快照转储内存快照比较内存快照完整例子三、使用WinDbg定位获取堆信息查看指定堆的使用情况获取地址信息获取…

【Docker】初级篇

【Docker】初级篇&#xff08;一&#xff09;Docker简介【1】docker是什么【2】容器与虚拟机比较【3】能干嘛【4】去哪下&#xff08;二&#xff09;Docker安装【1】前提说明【2】Docker的基本组成【3】安装步骤&#xff08;1&#xff09;确定是CentOS7及以上版本&#xff08;2…

抽烟打电话行为识别系统 yolo

抽烟打电话行为识别系统通过yolo深度学习框架模型&#xff0c;对现场画面区域进行7*24小时实时监测&#xff0c;发现抽烟打电话等违规行为立即抓拍存档预警。YOLOv5是一种单阶段目标检测算法&#xff0c;该算法在YOLOv4的基础上添加了一些新的改进思路&#xff0c;使其速度与精…

【 shell 编程 】第4篇 数组和函数

数组和函数 文章目录数组和函数一、数组1.普通数组2.关联数组3.数组和循环二、函数1.定义函数2.调用函数一、数组 变量&#xff1a;用一个固定的字符串&#xff0c;代替一个不固定字符串。 数组&#xff1a;用一个固定的字符串&#xff0c;代替多个不固定字符串。 1.普通数组…

Python代码实现学生管理系统

Python代码实现学生管理系统 需求说明 实现一个命令行版本的学生管理系统 功能: 新增学生 显示学生 查找学生 删除学生 存档到文件 创建入口函数 使用一个全局列表 students 表示所有学生信息. 使用 menu 函数和用户交互. 这是一个自定义函数. 使用 insert , show ,…

MacOS Ventura安装失败的原因及解决方法分享

2022年10月&#xff0c;苹果公司向Mac电脑用户推送了MacOS Ventura正式版更新&#xff0c;此次更新为MacOS带来了台前调度、连续互通相机、iMessage 撤回、编辑等功能。吸引众多Mac电脑用户不由纷纷下载安装&#xff0c;但各用户在安装的过程中经常遇到更新MacOS Ventura时突然…

物联网与射频识别技术,课程实验(五)

实验5—— 基于随机二进制树的防冲突算法的实现与性能分析 实验说明&#xff1a; 利用Python或Matlab模拟基于随机二进制树的防冲突算法&#xff1b; 分析标签数量k对遍历所有标签所需时间的影响&#xff1b; 分析标签ID的长度、分布对算法性能的影响&#xff1b; 利用Python或…

MQTT+STM32+ESP8266-01s硬件传递的JSON数据到前端和后端出现中文乱码问题

最近在做一个关于MQTT相关毕设项目,数据传输过程中出现了中文乱码问题,大致就是硬件发送的JSON主题数据中包含中文(如下图1所示),软件后端和软件前端接受该主题数据后出现了中文乱码,出现乱码一般都是硬件传递到后端和前端的编码不一致导致的,所以前端和后端接受该JSON数据的时…

2023.1.1 学习周报

文章目录摘要文献阅读1.题目2.摘要3.问题和方案4.介绍5.方法5.1 Symbolic Description5.2 The Short-Term Memory Priority Model5.3 The STAMP Model5.4 The Short-Term Memory Only Model6.实验6.1 评价指标6.2 实验结果7.结论深度学习加性模型点积模型缩放点积模型双线性模型…

数值优化之凸函数

本文ppt来自深蓝学院《机器人中的数值优化》 目录 1 凸函数的性质 ​2 凸函数的性质 1 凸函数的性质 凸函数最重要的性质就是Jensens inequality,也就是琴生不等式。 若能取到等号则是凸函数&#xff0c;若不能取到等号则是强凸函数&#xff0c;若不等号相反&#xff0c;则…

spring session

文章目录Spring Session 架构及应用场景为什么要spring-sessionSR340规范与spring-session的透明继承Spring Session探索特点核心 APIservlet session 与 spring-session 关系webflux 与 spring session 的关系基于 Servlet 的 Spring Session 实现思考题背景1、注册到 Filter …

Java 并发编程知识总结【一】

JUC 是什么&#xff1f; java.util.concurrent 在并发编程中使用的工具类 concurrent:并发 1. 线程基础知识复习 1.1 进程(process) 进程是程序的一次执行过程&#xff0c;或是正在运行的一个程序。是一个动态的过程&#xff1a;有它自身的产生、存在和消亡的过程(生命周期…

【数据集7】全球人类住区层GHSL数据详解

全球人类住区层Global Human Settlement Layer 官网地址-GHSL - Global Human Settlement Layer 1 全球人类住区层GHS-SMOD Global human settlement layer-settlement model grid (GHS-SMOD)&#xff1a;描述 epoch时段: 1975-2030年 5年一个周期resolution空间分辨率: …

Codeforces Round #833 (Div. 2)E. Yet Another Array Counting Problem(笛卡尔树+树形DP)

题目链接&#xff1a;Problem - E - Codeforces 样例输入&#xff1a; 4 3 3 1 3 2 4 2 2 2 2 2 6 9 6 9 6 9 6 9 9 100 10 40 20 20 100 60 80 60 60样例输出&#xff1a; 8 5 11880 351025663题意&#xff1a;给定一个长度为n的数组a[],对于每一个区间[l,r]&#xff0c;这个…

[Python从零到壹] 六十一.图像识别及经典案例篇之基于纹理背景和聚类算法的图像分割

祝大家新年快乐&#xff0c;阖家幸福&#xff0c;健康快乐&#xff01; 欢迎大家来到“Python从零到壹”&#xff0c;在这里我将分享约200篇Python系列文章&#xff0c;带大家一起去学习和玩耍&#xff0c;看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲…

尚医通-查询删除科室接口-添加查询删除排班接口实现(二十)

目录&#xff1a; &#xff08;1&#xff09;数据接口-查询和删除科室接口-功能实现 &#xff08;2&#xff09;数据接口-排版接口-功能实现 &#xff08;1&#xff09;数据接口-查询和删除科室接口-功能实现 查看医院系统中查询科室的对应的方法 查询条件需要用的类&#…

【数据结构】链式存储:链表

目录 &#x1f947;一&#xff1a;初识链表 &#x1f392;二、链表的实现&#xff08;单向不带头非循环&#xff09; &#x1f4d8;1.创建节点类 &#x1f4d2;2.创建链表 &#x1f4d7;3.打印链表 &#x1f4d5;4.查找是否包含关键字key是否在单链表当中 &#x1f4d9;…