java基础(并发编程)-设计模式~同步模式之保护性暂停

news2024/12/24 0:23:12

一、同步模式之保护性暂停定义

保护性暂停即Guarded Suspension,用在一个线程等待另一个线程的执行结果。

要点

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

代码实例 

public class GuardedObject {
    //结果
    private Object response;

    /**
     * 获取结果
     * @param timeout:表示要等待的超时时间,单位毫秒
     * @return Object
     */
    public Object getResponse(long timeout){
        synchronized (this){
            //开始时间
            long beginTime = System.currentTimeMillis();
            //已经等待时间
            long passedTime = 0;
            while(response == null){
                //这一轮循环应该等待的时间
                long waitTime = timeout - passedTime;
                //经历的时间超过了超时时间,则退出循环,不再等待
                if(waitTime<=0){
                    break;
                }
                //等待结果
                try {
                    //此处的wait时间为剩余的最大等待时间,如果中间被虚假唤醒,再次进入循环时,wait的等待时间会越来越小
                    this.wait(waitTime);
                }catch (Exception e){
                    e.printStackTrace();
                }
                //经历的等待时间
                passedTime = System.currentTimeMillis()-beginTime;
            }
            return response;
        }
    }

    public void generateResponse(Object response){
        synchronized (this){
            //给结果成员变量赋值
            this.response = response;
            this.notifyAll();
        }
    }

}

 测试代码实例

@Slf4j
public class TestGuarded {
    public static void main(String[] args){
        GuardedObject obj = new GuardedObject();
        //线程1 等待线程2的结果
        new Thread(()->{
            log.info("begin......");
            //2000表示最多等待2秒,2秒后不论是否拿到结果,都会返回response
            Object response = obj.getResponse(3000);
            log.info("结果为{}",response);

        },"t1").start();

        new Thread(()->{
            log.info("begin......");
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
            obj.generateResponse(12);
        },"t2").start();
    }
}

测试结果

10:46:42.839 [t2] INFO com.atorientsec.TestGuarded - begin......
10:46:42.839 [t1] INFO com.atorientsec.TestGuarded - begin......
10:46:43.857 [t1] INFO com.atorientsec.TestGuarded - 结果为12

二、线程同步模式扩展

 解耦的中间类代码示例:

/**
 * 解耦多线程的中间类,通用的类
 */
public class Mailboxes {
    private static Map<Integer,GuardedObject> boxes= new ConcurrentHashMap<>();
    private static int id =0;
    //产生唯一的id
    private 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();
    }
}

GuardedObject改造后的代码示例:

//保护性暂停模式:一个等待者对应一个结果生产者
public class GuardedObject {
    //结果
    private Object response;
    //标识GuardedObject
    private int id;

    public GuardedObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    /**
     * 获取结果
     * @param timeout:表示要等待的超时时间,单位毫秒
     * @return Object
     */
    public Object getResponse(long timeout){
        synchronized (this){
            //开始时间
            long beginTime = System.currentTimeMillis();
            //已经等待时间
            long passedTime = 0;
            while(response == null){
                //这一轮循环应该等待的时间
                long waitTime = timeout - passedTime;
                //经历的时间超过了超时时间,则退出循环,不再等待
                if(waitTime<=0){
                    break;
                }
                //等待结果
                try {
                    //此处的wait时间为剩余的最大等待时间,如果中间被虚假唤醒,再次进入循环时,wait的等待时间会越来越小
                    this.wait(waitTime);
                }catch (Exception e){
                    e.printStackTrace();
                }
                //经历的等待时间
                passedTime = System.currentTimeMillis()-beginTime;
            }
            return response;
        }
    }

    public void generateResponse(Object response){
        synchronized (this){
            //给结果成员变量赋值
            this.response = response;
            this.notifyAll();
        }
    }

}

测试代码示例:

@Slf4j
public class TestGuarded {
    public static void main(String[] args){
        for (int i = 0; i < 3; i++) {
            new People().start();
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        try {
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }

        for (Integer id:Mailboxes.getIds()) {
            new Postman(id,"内容"+id).start();
        }
    }
}

/**
 * 收信
 */
@Slf4j(topic = "c.People")
class People extends Thread{

    @Override
    public void run(){
        GuardedObject guardedObject = Mailboxes.createGuardedObject();
        log.info("开始收信,id:{}",guardedObject.getId());
        Object response = guardedObject.getResponse(5000);
        log.info("收到信,id:{},内容:{}",guardedObject.getId(),response);
    }
}

@Slf4j(topic = "c.Postman")
class Postman extends Thread{
    private int id;
    private String mail;
    public Postman(int id,String mail){
        this.id = id;
        this.mail = mail;
    }
    @Override
    public void run(){
        GuardedObject guardedObject = Mailboxes.getGuardedObject(id);
        log.info("送信 id:{},内容:{}",id,mail);
        guardedObject.generateResponse(mail);
    }
}

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

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

相关文章

Covex combination和affine combination

Covex combination和affine combination是两种常见的线性组合方法。 Covex combination&#xff08;凸组合&#xff09;是指在线性组合中&#xff0c;所有权重&#xff08;coefficients&#xff09;取非负值且总和为1的情况。也就是说&#xff0c;对于给定的一组向量或点集合&…

Linux系统编程:详解进程地址空间

目录 一. 进程空间的布局 二. 进程地址空间 2.1 早期CPU访问物理内存的方式 2.2 什么是虚拟地址&#xff08;进程地址空间&#xff09; 2.3 操作系统对地址空间的管理方法 三. 地址空间存在的意义 四. 总结 一. 进程空间的布局 在语言层面学习C/C时&#xff0c;根据变量…

android studio 单独运行java 文件

首先&#xff0c;创建一个新的java文件。 然后&#xff0c;在Test.java文件中写上如图所示的代码。 接下来&#xff0c;我们把目录模式从Android转换成Project。 打开.idea文件夹下的gradle.xml文件。 在gradle.xml文件中添加上红色方框中的内容。 <option name"delega…

MySQL GROUP BY 多个字段的用法说明

MySQL GROUP BY 多个字段的用法说明 1. 说明2. 举例附录 1. 说明 在 mysql 中使用 group by 的意思是分组查询。如果 group by 后面跟的是单个字段&#xff0c;那么表示按照这个字段分组查询&#xff0c;如果 group by 后面跟的是多个字段&#xff0c;那么表示按照这些字段的不…

关于使用idea中遇到给Dependencies没有加入jar包,但是在war_exploded中lib有

lib文件夹无jar包 Dependencies无jar包 war_exploded中存在此jar 原因是在此有jar包 当去掉时

深入解析 css.1.5

❑ 控制选择器的优先级。 ❑ 不要混淆层叠和继承。 ❑ 某些属性会被继承&#xff0c;包括文本、列表、表格边框相关的属性。 ❑ 不要混淆initial和auto值。 initial是一个CSS属性的初始值&#xff0c;它会将属性的值重置为浏览器默认值。例如&#xff0c;如果将background-co…

其实失败才是人生常态,赢者通吃确实存在,但那不代表绝大多数人。

其实失败才是人生常态&#xff0c;赢者通吃确实存在&#xff0c;但那不代表绝大多数人。 &#x1f4e2;今年的就业难度可能是之前5年最难的一年&#xff0c;也有可能是以后5年最好的一年。 &#x1f4e2;&#x1f4e2;疫情的回落&#xff0c;仿佛只带动了旅游业的发展&#x…

在EasyCVR中调用快照接口返回404是什么原因?如何解决?

EasyCVR视频融合平台基于云边端一体化架构&#xff0c;能在复杂的网络环境中将前端设备进行统一集中接入&#xff0c;实现视频资源的汇聚管理、直播鉴权、转码处理、多端分发、智能告警、数据共享等能力与服务。此外&#xff0c;平台也提供了丰富的API接口供用户自由调用、集成…

【XKCD】XKCD 风格的图像

目录 1. XKCD 2. 实战 1. XKCD xkcd是一种风格独特的漫画风格&#xff0c;以幽默、讽刺、科学和技术为主题。这种风格通常采用简单的线条和草图&#xff0c;表达出作者的思考和观点。xkcd的图像经常涉及科学、数学、计算机科学、社会和文化问题&#xff0c;以及作者个人的生…

181_带你体验 Power BI 开发者模式 pbip

181_带你体验 Power BI 开发者模式 pbip 一、背景 如果你是一个 Power BI 重度用户&#xff0c;你是不是也有如下的情况&#xff1f; 是的&#xff0c;Power BI 的版本控制全靠复制一份重命名来实现&#xff0c;而且版本之间的特点和差异时间久了就不记得了&#xff0c;还要加…

人工智能将怎样改变未来?TVP读书会带你探索!

引言 数十年前&#xff0c;图灵抛出的时代之问“机器能思考吗&#xff1f;”&#xff0c;将 AI 从科幻拉至现实&#xff0c;随着无数计算机科学先驱的共同努力&#xff0c;人工智能已经发展为引领未来的战略性技术。 AI 无处不在&#xff0c;智能时代触手可及&#xff0c;从 NL…

小程序 view clearfix 不起作用,边距还是被折叠

问题&#xff1a; 多个同级view情况下设置最后view clearfix&#xff0c;让底部露一些空白局域&#xff0c;此时clearfix不启作用。 .wxss .clearfix:before,.clearfix:after{content: "";clear: both;display: table;border-bottom: 1px solid black; } /*边距*/…

软件测试金字塔是什么,它的目的是什么,以及它包含哪些层次?

一、测试金字塔的概念&#xff1a; 测试金字塔是2009年Mike Cohn在他的著作《Succeeding with Agile》一书正式提出的。他是一个类比的概念&#xff0c;形容每一层&#xff0c;或者说不同集成阶段测试覆盖率和知行效率之间的一个相对关系。 测试金字塔最初的原型分三层&#…

如何找回删除的文件?这些文件恢复方法,超实用!

大家快看看我&#xff01;我一不小心删除了非常重要的文件&#xff0c;突然不知道该怎么办了&#xff01;我对电脑的操作也不熟悉&#xff0c;不敢轻易进行操作&#xff01;大家有什么比较好的方式可以找回删除的文件吗&#xff1f; 在使用电脑时&#xff0c;误删文件的情况经常…

基于Python所写的五子棋设计

点击以下链接获取源码资源&#xff1a; https://download.csdn.net/download/qq_64505944/87952977 《五子棋&#xff08;控制台版&#xff09;》程序使用说明 在PyCharm中运行《五子棋&#xff08;控制台版&#xff09;》即可进入如图1所示的系统主界面。 图1 游戏主界面 具…

掌握客户参与:终极指南有效的CRM管理

随着信息技术的快速发展&#xff0c;企业面对的市场竞争日益激烈&#xff0c;客户需求也变得越来越多样化和个性化。传统的销售和营销模式已经不能适应当前的市场环境&#xff0c;企业需要更加精细化、个性化的管理客户关系。CRM管理应用解决方案应运而生&#xff0c;它能够帮助…

allure环境搭建教程

pytest的安装:&#xff08;这里着重介绍Windows&#xff09; allure是基于Java的一个程序&#xff0c;需要Java1.8的环境,所以安装之前需要配置jdk环境 pytest是python的一个第三方单元测试框架&#xff0c;在这里用于生成原始的执行结果。 一、一定别选最新的&#xff0c;3.…

新品上市:ATA-2048高压放大器技术参数、特点及应用

作为中国电子测试仪器行业的优秀民族企业之一&#xff0c;Aigtek安泰电子始终坚持国产替代的发展战略&#xff0c;将产品研发和市场需求紧密结合&#xff0c;实现高效的研发产出&#xff0c;现已拥有ATA系列功率放大器、ATA系列功率放大器模块、ATG系列功率信号源、ATS系列高精…

SpringBoot + Vue前后端分离项目实战 || 五:用户管理功能后续

系列文章&#xff1a; SpringBoot Vue前后端分离项目实战 || 一&#xff1a;Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二&#xff1a;Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三&#xff1a;Spring Boot后端与Vue前端连接 SpringBoot V…

vscode调试python配置

{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387"version": "0.2.0","configurations": [{"name": "Python: 当前文…