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. 访问ajax请求后的结果

    let getJPM = (function() { let result; let url ="xxx"; $.ajax({ type: "post", ur ...

  2. ABC 210

    A 按题意模拟. scanf("%lld%lld%lld%lld",&n,&a,&x,&y); std::cout<<n * x - ( ...

  3. 洛谷 P6072 -『MdOI R1』Path(回滚莫队+01-trie)

    题面传送门 又是 ix35 神仙出的题,先以 mol 为敬 %%% 首先预处理出根节点到每个点路径上权值的异或和 \(dis_i\),那么两点 \(a,b\) 路径上权值的异或和显然为 \(dis_a ...

  4. NOIP 2020 游记

    第一次写比赛游记,请多多指教! I. 考前 由于最近参加了太多太多比赛了,所以没有敲模板题: 考前一周:主要是在做 AtCoder 的题和 xjoi 的模拟赛,相当于恶补了一些套路吧! 考前一天:上午 ...

  5. 代码整洁之道Clean Code笔记

    @ 目录 第 1 章 Clean Code 整洁代码(3星) ?为什么要整洁的代码 ?什么叫做整洁代码 第 2 章 Meaningful Names 有意义的命名(3星) 第 3 章 Function ...

  6. 【GS应用】基因组选择在杂交玉米上的应用示例

    目录 GS两步走 示例 缩短周期和成本 分类 杂交类型 试验研究 选择响应 选择的强度 选择的周期 预测能力 数据分析的注意事项 GS实施 优缺点 GS的成功 展望 GS两步走 示例 缩短周期和成本 ...

  7. Python基础之字典内置方法

    目录 1. 字典 1.1 字典的作用 1.2 创建和使用字典 1.2.1 dict类 1.2.2 基本的字典操作 1.2.3 字典方法 1. 字典 映射:可以通过名称来访问其各个值的数据结构. 字典是 ...

  8. 充分利用nginx的reload功能平滑的上架和更新业务

    以前更新我们都要停服务更新,不管什么时候更新,都可能有客户在访问,体验不好,二是如果有数据传输,可能会造成数据丢失. nginx reload可以不间断更新配置文件,原理就是当我们修改配置文件发起re ...

  9. android studio 编译NDK android studio 生成.so文件

    详细配置使用请移步:https://www.jianshu.com/p/4c7d9a10933b android studio NDK 编译 第一步: app/build.gradle下面 添加代码: ...

  10. 【编程思想】【设计模式】【基础模式Fundamental】delegation_pattern

    Python版 https://github.com/faif/python-patterns/blob/master/fundamental/delegation_pattern.py #!/usr ...