现在编码的时候,为了处理消息,大家动不动就上个重器,例如MQ之类的。但很多时候,并不是那么有必要,因为数据量和并发其实远远不够。

可以替代的方案非常多,其中一个是java.util.concurrent。

在jdk9及其以上,java.util.Observable已经被标注为过时,官方推荐使用java.beans或者是java.util.concurrent。

在发布订阅者模式中,有四个对象是需要关注的:

  1. 发布者
  2. 订阅者(消费者)
  3. 消息
  4. 并发

本文主要代码参考 https://www.cnblogs.com/zhangmingda/p/14715139.html

不过为了更加友好一些,对原有的代码做了适量的调整。

注:以下代码运行于windows11+JDK17

消息对象

package study.base.designPattern.observer.latest.flow;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; public class Message {
private Integer qty;
private Integer maxQty;
private String content;
private Map<String, Boolean> readStatus; public Map<String, Boolean> getReadStatus() {
return readStatus;
} public String getContent() {
return content;
} public boolean isFinished() {
return qty.intValue() == maxQty.intValue();
} public Message(String content, List<String> readerList) {
this.content = content;
this.maxQty = readerList.size();
this.qty = 0;
this.readStatus = new ConcurrentHashMap<>();
for (String item : readerList) {
readStatus.put(item, false);
}
} public void read(String readerName) {
if (qty < maxQty) {
if (readStatus.containsKey(readerName)) {
Boolean isRead = readStatus.get(readerName);
if (!isRead) {
synchronized (readStatus) {
readStatus.put(readerName, true);
qty++;
System.out.println("---|"+readerName + "正在进行" + this.content + "...." + qty);
if (qty==maxQty) {
System.out.println("\n---|所有人已经完成【"+this.content+"】\n");
}
}
}
}
} }
}

消费者对象

package study.base.designPattern.observer.latest.flow;

import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription; public class Student implements Subscriber<Message> { private Subscription subscription;
private String name; public Student(String name) {
this.name = name;
} @Override
public void onSubscribe(Subscription subscription) {
System.out.println(name + "开始订阅[" + subscription.toString() + "]");
subscription.request(1);
this.subscription = subscription;
} @Override
public void onError(Throwable e) {
System.out.println(e.getMessage());
} @Override
public void onComplete() {
System.out.println(name + "关闭了订阅");
Teacher.getLock().lock();
Teacher.getCondition().signalAll();
Teacher.getLock().unlock(); } @Override
public void onNext(Message message) {
message.read(this.name);
subscription.request(1);
/**
* 模拟延时--郊游的时候,时间长一些
*/
try {
if (message.getContent().equals("郊游")) {
Thread.sleep(1300);
}
else {
Thread.sleep(200);
} } catch (InterruptedException e) {
e.printStackTrace();
} } }

发布者和主程序

package study.base.designPattern.observer.latest.flow;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.SubmissionPublisher;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature; /**
* https://www.cnblogs.com/zhangmingda/p/14715139.html 此类技术是观察者模式的一个并发实现
*
* @author lzfto
*/
public class Teacher {
private static Lock lock = new ReentrantLock(true);
private static Condition condition = lock.newCondition(); private volatile static CopyOnWriteArrayList<Message> subjectList = new CopyOnWriteArrayList<Message>(); public static Lock getLock() {
return lock;
} public static Condition getCondition() {
return condition;
} public static void main(String[] args) throws InterruptedException { /**
* 定义一个发布者,需要设定要发送消息的泛型数据类型
*/
SubmissionPublisher<Message> teacher = new SubmissionPublisher<>();
/**
* 定义一个订阅者
*/
List<String> studentList = Arrays.asList("mzd", "***", "luzhfiei", "海瑞");
for (String readerName : studentList) {
Student student = new Student(readerName);
teacher.subscribe(student);
}
/**
* 测试发布消息
*/ subjectList.add(new Message("朗读", studentList));
subjectList.add(new Message("劳动", studentList));
subjectList.add(new Message("郊游", studentList));
subjectList.add(new Message("射箭", studentList)); subjectList.forEach(item -> {
System.out.println("同学们!开始【" + item.getContent() + "】");
teacher.submit(item);
}); // 向订阅者发布数据,需要保持主线程存活,否则当前线程执行结束,发布者和订阅者都被销毁了。
/**
* 关闭消息发布
*/
teacher.close(); // 关闭后,如果当前线程未退出,待订阅者所有消息都处理完毕才会运行订阅者的onComplete方法
lock.lock();
condition.await();
lock.unlock();
System.out.println(JSONArray.toJSONString(subjectList, SerializerFeature.PrettyFormat));
;
} }

测试后的输出(一种情况):

mzd开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@12749d9e]
***开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@1df086d4]
luzhfiei开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@1e7629c2]
海瑞开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@73e441ec]
同学们!开始【朗读】
同学们!开始【劳动】
同学们!开始【郊游】
同学们!开始【射箭】
---|mzd正在进行朗读....1
---|海瑞正在进行朗读....2
---|luzhfiei正在进行朗读....3
---|***正在进行朗读....4 ---|所有人已经完成【朗读】 ---|海瑞正在进行劳动....1
---|luzhfiei正在进行劳动....2
---|***正在进行劳动....3
---|mzd正在进行劳动....4 ---|所有人已经完成【劳动】 ---|***正在进行郊游....1
---|mzd正在进行郊游....2
---|luzhfiei正在进行郊游....3
---|海瑞正在进行郊游....4 ---|所有人已经完成【郊游】 ---|mzd正在进行射箭....1
---|***正在进行射箭....2
---|luzhfiei正在进行射箭....3
---|海瑞正在进行射箭....4 ---|所有人已经完成【射箭】 luzhfiei关闭了订阅
***关闭了订阅
mzd关闭了订阅
海瑞关闭了订阅

subjectList的结果:

[
{
"content": "朗读",
"finished": true,
"readStatus": {
"mzd": true,
"海瑞": true,
"***": true,
"luzhfiei": true
}
},
{
"content": "劳动",
"finished": true,
"readStatus": {
"mzd": true,
"海瑞": true,
"***": true,
"luzhfiei": true
}
},
{
"content": "郊游",
"finished": true,
"readStatus": {
"mzd": true,
"海瑞": true,
"***": true,
"luzhfiei": true
}
},
{
"content": "射箭",
"finished": true,
"readStatus": {
"mzd": true,
"海瑞": true,
"***": true,
"luzhfiei": true
}
}
]

这只是一个非常简单的例子,距离生产还有很远的一个距离。

java并发的发布和订阅测试的更多相关文章

  1. 转MQTT--Python进行发布、订阅测试

    前言  使用python编写程序进行测试MQTT的发布和订阅功能.首先要安装:pip install paho-mqtt 测试发布(pub)  我的MQTT部署在阿里云的服务器上面,所以我在本机上编写 ...

  2. Java并发--安全发布对象

    单例模式 懒汉模式:多线程非线程安全,在多线程中,可能会产生多个对象 饿汉模式:线程安全. 类加载的时候初始化,不推荐在构造函数需要做耗时操作的时候使用,因为可能导致类加载缓慢,而且可能初始化后并没有 ...

  3. MQTT介绍(3)java模拟MQTT的发布,订阅

    MQTT目录: MQTT简单介绍 window安装MQTT服务器和client java模拟MQTT的发布,订阅 在此强调一下mqtt的使用场景: 1.不可靠.网络带宽小的网络 2.运行的设备CPU. ...

  4. Java实现Redis的消息订阅和发布

    1.  首先需要一个消息监听器类 package com.sogou.baike.testimport.testSubscribe; import redis.clients.jedis.JedisP ...

  5. java 多线程 发布订阅模式:发布者java.util.concurrent.SubmissionPublisher;订阅者java.util.concurrent.Flow.Subscriber

    1,什么是发布订阅模式? 在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者).而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话 ...

  6. Java高并发--安全发布对象

    Java高并发--安全发布对象 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 发布对像:使一个对象能够被当前范围之外的对象使用. 对象逸出:一种错误的发布.当一个对象 ...

  7. windows环境下apache-apollo服务器搭建及发布订阅测试

    查证了一些资料之后,发现 apache-apollo服务器使用的人还是挺多的,资料也比较齐全,所以直接选择 apache-apollo了,具体性能如何,先用起来再说吧: 1.下载 apache-apo ...

  8. 《java并发编程实战》读书笔记2--对象的共享,可见性,安全发布,线程封闭,不变性

    这章的主要内容是:如何共享和发布对象,从而使它们能够安全地由多个线程同时访问. 内存的可见性 确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化. 上面的程序中NoVisibility可能 ...

  9. Java并发编程(五):Java线程安全性中的对象发布和逸出

    发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外 ...

  10. java并发编程笔记(四)——安全发布对象

    java并发编程笔记(四)--安全发布对象 发布对象 使一个对象能够被当前范围之外的代码所使用 对象逸出 一种错误的发布.当一个对象还没构造完成时,就使它被其他线程所见 不安全的发布对象 某一个类的构 ...

随机推荐

  1. [Docker] 镜像源配置 for Linux

    $ vi /etc/docker/daemon.json { "registry-mirrors": [ "https://docker.mirrors.ustc.edu ...

  2. WPF 使用 Silk 的 Direct2D 入门

    在上一篇博客的基础上,使用 dotnet 基金会新开源的 Silk.NET 库,让 Silk.NET 创建的 DX 设备和 WPF 对接渲染.接下来本文将告诉大家如何使用 Silk.NET 提供的 D ...

  3. WPF 制作一个加密文件夹应用

    我有一个需求就是将我的一些文件夹的内容同步到网盘上面去.但是我是不信任现在的各个网盘的,网盘的数据被我认为是会被泄露的数据,我需要同步的文件夹中,可能存在隐私的数据.于是我就想到了将文件夹里面的内容进 ...

  4. ES6中Promise方法详解

    概要 Promise是个保存异步结果的容器(对象). Promise的状态有:pending(进行中),fulfilled(已成功),rejected(已失败),对应其异步操作的状态. 状态转换: p ...

  5. 日志服务 HarmonyOS NEXT 日志采集最佳实践

    背景信息 随着数字化新时代的全面展开以及 5G 与物联网(IoT)技术的迅速普及,操作系统正面临前所未有的变革需求.在这个背景下,华为公司自主研发的鸿蒙操作系统(HarmonyOS)应运而生,旨在满足 ...

  6. 关于Web的欢迎页面的开发设置

    关于Web的欢迎页面的开发设置 每博一文案 命运总是不如人愿.但往往是在无数的痛苦中,在重重的矛盾和艰辛中,才是人成熟起来. 一次邂逅,一次目光的交融,就是永远的合二为一,就是与上帝的契约:总是风暴雷 ...

  7. 远程控制软件 Teamviewer、Splashtop、向日葵哪个好用

    ​ 编辑切换为居中 添加图片注释,不超过 140 字(可选) 好用的远程控制软件,我一般只推荐这三个经典品牌: Teamviewer.Splashtop.向日葵. Teamviewer 来自德国,妥妥 ...

  8. 前后端分离项目集成PageOffice——实现在线编辑Word文件的版本控制

    PageOffice本身提供了SaveFilePage的js方法,但是由于该方法不支持代理且不能跨域导致在前后端分离项目中无法使用 功能:实现三个按钮分别保存不同版本的文件 1.PageOffice可 ...

  9. 「Python实用秘技17」快速获取国内节假日安排

    本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第17 ...

  10. Stenciljs 学习之搭建项目

    框架介绍 stenciljs 是用于构建可重用.可扩展的设计系统的工具链.生成在每个浏览器中运行的小型.超快且 100% 基于标准的 Web Component. 更对介绍请参考官方网站 创建项目 使 ...