1,什么是发布订阅模式?

在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。
Java9开始新增了一个发布-订阅框架,框架是基于异步响应流。发布,订阅框架可以非常方便地处理异步线程之间的流数据交换( 比如两个线程之间需要交换数据) 而且这个发布、订阅框架不需要使用数据中心来缓冲数据,同时具有非常高效的性能。

2,发布订阅模式的4个角色

  1. Flow.Publisher: 代表数据发布者,生产者
  2. Flow.Subscriber: 表数据订阅者、消费者
  3. Flow.Subscription: 表发布者和订阅者之间的链接纽带。订阅者既可通过调用该对象的request()方法来获取数据项,也可通过调用对象的cancel()方法来取消订阅。
  4. Flow.Processor: 数据处理器,它可同时作为发布者和订阅者使用

测试用例:发布者每秒钟发布一条消息,订阅者每秒钟订阅一条消息。

注意:订阅者处理消息,依赖当前线程的存活状态,如果发布消息后当前程序代码运行完毕会立即退出,订阅者来不及执行任何程序。

此例 用锁保持当前线程存活

import java.util.List;
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @ClassName PublisherFlowSubscriber
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/28.
*/
public class PublisherFlowSubscriber {
/**
* 定义用来保持线程不退出的锁
*/
private static Lock lock = new ReentrantLock(true);
private static Condition condition = lock.newCondition(); public static void main(String[] args) throws InterruptedException {
/**
* 定义一个发布者,需要设定要发送消息的泛型数据类型
*/
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
/**
* 定义一个订阅者
*/
MySubscirber<String> subscirber = new MySubscirber<>("订阅者1");
MySubscirber<String> subscirber2 = new MySubscirber<>("订阅者2");
/**
* 通过发布者配置订阅者 会触发订阅者的onSubscribe方法,他们之间的链接纽带会通过参数传递给onSubscribe方法,如果注册失败会触发onError方法
*/
publisher.subscribe(subscirber);publisher.subscribe(subscirber2); /**
* 测试发布消息
*/
List<String> list = List.of("张三", "李四", "王五", "赵六");
list.forEach(string -> publisher.submit(string)); //向订阅者发布数据,需要保持前台的线程存活,否则当前线程执行结束,发布者和订阅者都被销毁了。
/**
* 关闭消息发布
*/
publisher.close(); //关闭后,如果当前线程未退出,待订阅者所有消息都处理完毕才会运行订阅者的onComplete方法
lock.lock();
//抛出锁
condition.await();
lock.unlock(); } /**
* 定义订阅者类,需要注意实现接口Flow.Subscriber 实现其泛型传递
*/
private static class MySubscirber<T> implements Flow.Subscriber<T>{
/**
* 订阅者自定义的属性,名字,关联的订阅平台
*/
private String name;
private Flow.Subscription subscription; public MySubscirber(String name) {
this.name = name;
} /**
* 订阅的时候触发的方法
* @param subscription 订阅者被关联的订阅平台
*/
@Override
public void onSubscribe(Flow.Subscription subscription) {
System.out.println(name + "开启订阅" + subscription);
/**
* 从订阅平台获取一条消息
*/
subscription.request(1);
/**
* 将平台实例保存,便于复用
*/
this.subscription = subscription;
} /**
* 获取一条数据后触发的方法
* @param
*/
@Override
public void onNext(T t) {
System.out.println(name + "获取到了一条数据:" +t);
//再次获取一条数据...自循环触发自己循环调用,一直将所有数据获取完毕
subscription.request(1);
/**
* 模拟处理耗时
*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} /**
* 订阅出错时运行的方法
* @param throwable 错误对象
*/
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
} /**
* 发布者停止发布,且订阅者处理完接收数据后,触发该方法
*/
@Override
public void onComplete() {
System.out.println(name + "发布者关闭了发布");
lock.lock();
condition.signalAll();
lock.unlock();
}
}
}

java 多线程 发布订阅模式:发布者java.util.concurrent.SubmissionPublisher;订阅者java.util.concurrent.Flow.Subscriber的更多相关文章

  1. Java 多线程编程之九:使用 Executors 和 ThreadPoolExecutor 实现的 Java 线程池的例子

    线程池用来管理工作线程的数量,它持有一个等待被执行的线程的队列.         java.util.concurrent.Executors 提供了 java.util.concurrent.Exe ...

  2. js里的发布订阅模式及vue里的事件订阅实现

    发布订阅模式(观察者模式) 发布订阅模式的定义:它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布订阅模式在JS中最常见的就是DOM的事件绑定与触发 ...

  3. java多线程 生产者消费者模式

    package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...

  4. Java多线程面试题整理

    部分一:多线程部分: 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. ...

  5. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

    概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...

  6. Java多线程系列目录(共43篇)

    最近,在研究Java多线程的内容目录,将其内容逐步整理并发布. (一) 基础篇 01. Java多线程系列--“基础篇”01之 基本概念 02. Java多线程系列--“基础篇”02之 常用的实现多线 ...

  7. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  8. Java多线程系列--“JUC锁”06之 Condition条件

    概要 前面对JUC包中的锁的原理进行了介绍,本章会JUC中对与锁经常配合使用的Condition进行介绍,内容包括:Condition介绍Condition函数列表Condition示例转载请注明出处 ...

  9. Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

    概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 ...

随机推荐

  1. GPG 使用指南

    加密与签名 在传输信息时,会面临两个典型的问题: 如何保证发出的消息,只能被预期的接收人获取? 如何保证收到的消息,确实由预期的发送人发出? 这两个问题不难理解.例如发送的邮件可能会被监听,诈骗分子可 ...

  2. Codeforces 1270E - Divide Points(构造+奇偶性)

    Codeforces 题目传送门 & 洛谷题目传送门 显然,直接暴力枚举是不可能的. 考虑将点按横纵坐标奇偶性分组,记 \(S_{i,j}=\{t|x_t\equiv i\pmod{2},y_ ...

  3. Atcoder Grand Contest 031 D - A Sequence of Permutations(置换+猜结论)

    Atcoder 题面传送门 & 洛谷题面传送门 猜结论神题. 首先考虑探究题目中 \(f\) 函数的性质,\(f(p,q)_{p_i}=q_i\leftarrow f(p,q)\circ p= ...

  4. P4497 [WC2011]拼点游戏

    P4497 [WC2011]拼点游戏 在我的 cnblogs 中查看 数据结构大杂烩 + 阿巴细节题. 调了三个小时. 首先考虑第一小问的答案. 注意到点数的计算方式是先负后正的形式,不妨看做选出 \ ...

  5. 【R】write.table输出数据带有行名?

    目录 问题 解决一 解决二 问题 这个问题应该很常见吧.R中输出数据框时,想要把行名和列名都输出.如果直接输出的话,输出的结果列名会往前移动一位,这显然不是我们想要的. 直接上例子: > a = ...

  6. MacBookpro安装VMware Fusion虚拟机,并安装win7 64位系统

    1.准备好安装用的东西(准备好正确的东西,安装路上就成功了一半)(1)VMware Fusion 附带注册机生成注册码,链接: https://pan.baidu.com/s/13Qm9zPOFjFt ...

  7. perl中tr的用法(转载)

    转载:http://blog.sina.com.cn/s/blog_4a0824490101hncz.html (1)/c表示把匹配不上的字符进行替换. $temp="AAAABCDEF&q ...

  8. 巩固javawbe第二天

    巩固内容: <!DOCTYPE> 声明 <!DOCTYPE>声明有助于浏览器中正确显示网页. 网络上有很多不同的文件,如果能够正确声明HTML的版本,浏览器就能正确显示网页内容 ...

  9. 🏆【Alibaba中间件技术系列】「Sentinel技术专题」分布式系统的流量防卫兵的基本介绍(入门源码介绍)

    推荐资料 官方文档 官方demo Sentinel 是什么? 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护 ...

  10. A Child's History of England.5

    Above all, it was in the Roman time, and by means of Roman ships, that the Christian Religion was fi ...