Java多线程设计模式之保护性暂挂模式

news2024/10/5 12:52:25

模式简介

多线程编程中,为了提高并发性,往往将一个任务分解为不同的部分。将其交由不同的线程来执行。这些线程间相互协作时,仍然可能会出现一个线程等待另一个线程完成一定的操作,其自身才能继续运行的情形。

保护性暂挂模式(Guarded Suspension)可以帮助我们解决上述的等待问题。该模式的核心思想是如果某个线程执行特定的操作前需要满足一定的条件,则在该条件未满足时将该线程暂停运行(即暂挂线程,使其处于waiting状态,直到该条件满足时才继续运行)。wait/notify可以用来实现保护性暂挂模式,但是,该模式还要解决wait/notify所解决的问题之外的问题。

模式架构

保护性暂挂模式的 核心是一个受保护的方法,该方法执行其所要真正执行的操作时需要满足特定的条件(Predicate),当条件不满足时,执行受保护方法的线程会被挂起进入等待状态,直到该条件满足时线程才会继续运行。 其类图如下所示:

在这里插入图片描述

  1. GuardedObject:包含受保护方法的对象,其主要方法及职责如下:

    • guardedMethod:受保护方法
    • stateChanged:改变GuardedObject实例状态的方法,该方法负责在保护条件成立时唤醒受保护方法的执行线程。
  2. GuardedAction:抽象了目标动作(受保护方法所要执行的操作),关联了目标动作所需的保护条件。其主要方法及职责如下

    • call:用户表示目标动作的方法
  3. ConcreteGuardedAction:应用程序所实现的具体目标动作极其关联的保护条件。

  4. Predicate:抽象了保护条件

    • evaluate:用于表示保护条件的方法
  5. ConcretePredicate:应用程序所实现的具体保护条件。

  6. Blocker:负责对执行guardedMethod的线程进行挂起和唤醒,并执行ConcreteGuardedAction所实现的目标操作,其方法及职责如下:

    • callWithGuard :负责执行目标操作和暂挂当前线程。
    • signalAfter:负责执行其参数指定的动作和唤醒由该方法所属Blocker实例所暂挂的线程中的一个线程。
    • signal:负责唤醒由该方法所述Blocker实例所暂挂的线程中一个线程。
    • broadcastAfter:负责执行其参数指定的动作和唤醒由该方法所属Blocker实例所暂挂的所有线程。
    • broadcast:负责唤醒由该方法所属Blocker实例暂挂的所有线程。
  7. ConditionVarBlocker:基于Java条件变量(java.util.concurrent.locks.Condition)实现的Blocker。

    其时序图如下
    在这里插入图片描述

    1. 客户端代码调用受保护方法guardedMethod。
    1. guardedMethod方法创建guardedAction实例
    1. guardedMethod 方法以guardedAction为参数调用Blocker实例的callWithGuard方法。
  • 4-5. callWithGuard方法调用guardedAction的getGuard方法获取保护条件Predicate。
  • 6-8. 循环判断保护条件是否成立,若保护条件成立,则循环退出。否则,循环将当前线程暂挂使其处于等待状态。当其他线程唤醒被暂挂的线程后,该循环仍然继续检测保护条件,并重复上述逻辑。
  • 9-10.callWithGuard方法调用guardedAction的call方法来执行目标动作,并记录call方法的返回值。
    1. callWithGuard将返回值返回给调用方。
    1. guardedMethod方法返回。

代码示例:

  1. GuardedObject中的guardedMethod方法。
    // 1. sendAlarm是一个受保护方法
    public void sendAlarm(final AlarmInfo alarm) throws Exception {
       // 2. 创建guardedAction实例
        GuardedAction<Void> guardedAction =
                new GuardedAction<Void>(agentConnected) {
                    public Void call() throws Exception {
                        doSendAlarm(alarm);
                        return null;
                    }
                };
	  //  3. 调用Blocker实例的callWithGuard方法。
        blocker.callWithGuard(guardedAction);
    }
  1. blocker实例中的callWithGuard方法
public <V> V callWithGuard(GuardedAction<V> guardedAction) throws Exception {
        lock.lockInterruptibly();
        V result;
        try {
        //  4-5. callWithGuard方法调用guardedAction的getGuard方法获取保护条件Predicate。
            final Predicate guard = guardedAction.guard;
            while (!guard.evaluate()) {
            //6-8:循环判断保护条件是否成立
                Debug.info("waiting...");
                condition.await();
            }
            // 9-10 callWithGuard方法调用guardedAction的call方法来执行目标动作,并记录call方法的返回值。
            result = guardedAction.call();
            return result;
        } finally {
            lock.unlock();
        }
    }

受保护方法的执行线程被暂挂后,当保护条件成立时,其他线程需要唤醒该线程.其序列图如下

在这里插入图片描述

    1. 客户端代码调用stateChanged方法改变GuardedObject实例状态,这些状态包含了保护条件所关心的状态。
    1. stateChanged方法创建java.util.concurrent.Callable实例stateOperation,stateOperation封装了改变GuardedObject实例状态所需的操作。
    1. stateChanged方法以stateOperation为参数,调用Blocker实例的signalAfter方法。
  • 4-5 signalAfter方法调用stateOperation对象的call方法以改变GuardedObject实例的状态,并记录其返回值shouldSignalBlocker
  • 6-7. signalAfter方法在shouldSignalBlocker值为true时,调用java.util.concurrent.locks.Condition实例的signal方法唤醒被该Condition实例所暂挂的线程中的一个线程。
    1. signalAfter方法返回,此时,执行受保护方法的线程可能已经被唤醒(取决于shouldSignalBlocker值是否为true)。

代码示例:

    protected void onConnected() {
        try {
          //2-3.创建stateOperation,调用Blocker实例的signalAfter方法
            blocker.signalAfter(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    connectedToServer = true;
                    Debug.info("connected to server");
                    return Boolean.TRUE;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void signalAfter(Callable<Boolean> stateOperation) throws Exception {
        lock.lockInterruptibly();
        try {
        //4-5 signalAfter方法调用stateOperation对象的call方法以改变GuardedObject实例的状态
            if (stateOperation.call()) {
            //调用java.util.concurrent.locks.Condition实例的signal方法唤醒被该Condition实例所暂挂的线程中的一个线程。
                condition.signal();
            }
        } finally {
            lock.unlock();
        }

    }

模式的评价与实现考量

关注点分离,保护性暂挂模式中的各个参与者各自仅关注本模式所要解决的问题中的一个方面,各个参与者的职责是高度内聚的。这使得保护性暂挂模式便于理解和应用,应用开发人员只需要根据应用的需要实现GuardedObject、ConcretePredicate、和ConcreteGuardedAction这几个必须由应用实现的参与者即可,而其他参与者的实现都是可复用的。

可能增加JVM垃圾回收的负担,为了使GuardedAction实例的call方法能够访问保护方法guardedMethod参数,我们需要利用闭包。因此,GuardedAction实例可能是在保护方法中创建的,这意味着,每次保护方法被调用的时候都会有个新的GuardedAction实例被创建。而这会增加JVM内存池的占用,从而增加垃圾回收的负担。

可能增加上下文切换,这点与保护性暂挂模式本身无关。只不过,不管如何实现该模式,只要这里面涉及线程的暂挂和唤醒就会引起上下文切换。如果频繁出现保护方法被调用时保护条件不成立,那么保护方法的执行线程就会频繁的被暂挂和唤醒,从而导致频繁的上下文切换。

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

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

相关文章

数据治理服务解决方案(35页WORD)

方案介绍&#xff1a; 本数据治理服务解决方案旨在为企业提供一站式的数据治理服务&#xff0c;包括数据规划、数据采集、数据存储、数据处理、数据质量保障、数据安全及合规等方面。通过构建完善的数据治理体系&#xff0c;确保企业数据的准确性、完整性和一致性&#xff0c;…

Excel 识别数据层次后转换成表格

某列数据可分为 3 层&#xff0c;第 1 层是字符串&#xff0c;第 2 层是日期&#xff0c;第 3 层是时间&#xff1a; A1NAME122024-06-03304:06:12404:09:23508:09:23612:09:23717:02:2382024-06-02904:06:121004:09:231108:09:2312NAME2132024-06-031404:06:121504:09:231620…

JPS(Jump Point Search)跳点搜索路径规划算法回顾

本篇文章主要回顾一下几年前学的JPS跳点搜索规划算法的相关内容&#xff0c;之前学的时候没有进行概括总结&#xff0c;现在补上 一、A*算法简单回顾 – 1、基本介绍和原理 A*&#xff08;A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法&#xff0c;也是解决许多…

RERCS系统开发实战案例-Part06 FPM Application添加列表组件(List UIBB)

在FPM Application中添加搜索结果的List UIBB 1&#xff09;添加List UIBB 2&#xff09;提示配置标识不存在&#xff0c;则需要新建配置标识&#xff08;* 每个组件都必须有对应的配置标识&#xff09;&#xff1b; 3&#xff09;选择对应的包和请求 4&#xff09;为List UIB…

简述spock以及使用

1. 介绍 1.1 Spock是什么&#xff1f; Spock是一款国外优秀的测试框架&#xff0c;基于BDD&#xff08;行为驱动开发&#xff09;思想实现&#xff0c;功能非常强大。Spock结合Groovy动态语言的特点&#xff0c;提供了各种标签&#xff0c;并采用简单、通用、结构化的描述语言…

【软件测试】软件测试入门

软件测试入门 一、什么是软件测试二、软件测试和软件开发的区别三、软件测试在不同类型公司的定位1. 无组织性2. 专职 OR 兼职3. 项目性VS.职能性4.综合型 四、一个优秀的软件测试人员具备的素质1. 技能相关2. 非技能相关 一、什么是软件测试 最常见的理解是&#xff1a;软件测…

设备保养计划不再是纸上谈兵,智能系统让执行更到位!

在物业管理的日常工作中&#xff0c;我们常常听到“设备保养台账”“设备保养计划”“设备保养记录”等等这些词&#xff0c;但你是否真正了解它们的含义&#xff1f;是否知道一个完善的设备保养计划、记录、台账对于物业运营的重要性&#xff1f;今天&#xff0c;我们就来深入…

AI产品经理,应掌握哪些技术?

美国的麻省理工学院&#xff08;Massachusetts Institute of Technology&#xff09;专门负责科技成果转化商用的部门研究表明&#xff1a; 每一块钱的科研投入&#xff0c;需要100块钱与之配套的投资&#xff08;人、财、物&#xff09;&#xff0c;才能把思想转化为产品&…

《纪元 1800》好玩吗? 苹果电脑能玩《纪元 1800》吗?

《纪元1800》是一款不错的策略游戏&#xff0c;这款游戏因为画面和玩法独特深受玩家们的喜爱。下面我们来看看《纪元 1800》好玩吗&#xff0c;苹果电脑能玩《纪元 1800》吗的相关内容。 一、《纪元1800》好玩吗 《纪元1800》是一款备受瞩目的策略游戏。下面让我们来看看这款…

mysql [Err] 1118 - Row size too large (> 8126).

1.找到my.ini文件 1.1 控制台输入以下指令&#xff0c;打开服务 services.msc1.2 查看mysql服务的属性 2.停止mysql服务&#xff0c;修改my.ini文件并且保存 innodb_strict_mode03.重启mysql服务 4.验证是否关闭成功 show variables like %innodb_strict_mode%; show vari…

SaaS产品运营|一文讲清楚为什么ToB产品更适合采用PLG模式?

在数字化时代&#xff0c;ToB&#xff08;面向企业&#xff09;产品市场的竞争愈发激烈。为了在市场中脱颖而出&#xff0c;许多企业开始转向PLG&#xff08;产品驱动增长&#xff09;模式。这种模式以产品为核心&#xff0c;通过不断优化产品体验来驱动用户增长和业务发展。本…

学本领、争奖金! 由和鲸支持的“数据蜂杯”全国大学生暑期面访调查大赛火热报名中

随着数字时代的到来&#xff0c;社会调查能力、数据分析能力成为当代大学生不可或缺的核心素养。为了进一步提升当代大学生深入田野、以团队的方式采集高质量数据的能力&#xff0c;中国人民大学中国调查与数据中心&#xff08;NSRC&#xff09;举办“数据蜂杯”全国大学生暑期…

头歌资源库(9)丢失的数字

一、 问题描述 二、算法思想 输入n和nums数组。初始化一个大小为n1的数组counts&#xff0c;初始值都为0。遍历nums数组&#xff0c;将counts[nums[i]]的值加1。遍历counts数组&#xff0c;找到第一个值为0的索引&#xff0c;即为没有出现在数组中的那个数。输出结果。 三、…

LabVIEW电表改装与校准仿真系统

LabVIEW开发的电表改装与校准仿真实验平台不仅简化了传统的物理实验流程&#xff0c;而且通过虚拟仿真提高了实验的效率和安全性。该平台通过模拟电表改装与校准的各个步骤&#xff0c;允许学生在没有实际硬件的情况下完成实验&#xff0c;有效地结合了理论学习和实践操作。 项…

51单片机宏定义的例子

代码 demo.c #include "hardware.h"void delay() {volatile unsigned int n;for(n 0; n < 50000; n); }int main(void) {IO_init();while(1){PINSET(LED);delay();PINCLR(LED);delay();}return 0; }cfg.h #ifndef _CFG_H_ #define _CFG_H_// #define F_CPU …

Ubuntu 20.04 LTS WslRegisterDistribution failed with error: 0x800701bc

1.以管理员身份运行powershell&#xff0c;输入&#xff1a;wsl --update&#xff0c; 2.重新打开ubuntu即可。

泛微开发修炼之旅--17基于Ecology短信平台,实现后端自定义二开短信发送方案及代码示例

文章链接&#xff1a;17基于Ecology短信平台&#xff0c;实现后端自定义二开短信发送方案及代码示例

【产品经理】ERP订单处理3-解密促销策略

由于订单到电商ERP系统中&#xff0c;订单金额已经不能支持改动&#xff0c;故电商前台端的优惠券活动、满减活动、支付优惠活动无法使用&#xff0c;故电商ERP只涉及赠品的活动。 一、订单金额阶梯送 顾名思义&#xff1a;订单金额在某个或者某几个金额范围内赠送商品。 字…

十进制、二进制、十六进制之间的相互转换

实验目的 实现int 、float 转换为字符串并显示 实现数字字符以二进制、十进制、十六进制显示 实现十进制、二进制、十六进制之间的相互转换 #include "numconvert.h" #include "ui_numconvert.h"NumConvert::NumConvert(QWidget *parent): QWidget(parent)…

Android平台如何实现多路低延迟RTSP|RTMP播放?

技术背景 实际上&#xff0c;我们在2015年做Android平台RTSP、RTMP播放模块的时候&#xff0c;第一版就支持了多实例播放&#xff0c;因为SDK设计比较灵活&#xff0c;做个简单的player实例封装即可实现多实例播放&#xff08;Android Unity的就有多路demo&#xff09;&#x…