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. Java设计模式之(十三)——模板方法模式

    1.什么是模板模式? Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. ...

  2. 模版 动态 dp

    模版 动态 dp 终于来写这个东西了.. LG 模版:给定 n 个点的数,点有点权, $ m $ 次修改点权,求修改完后这个树的最大独立集大小. 我们先来考虑朴素的最大独立集的 dp \[dp[u][ ...

  3. 【python】python之list

    1.判断list是否为空 方式一: list_temp=[] if len(list_temp): #非空即为真 print('list is not empty') else: print('lis ...

  4. Docker将容器制作成镜像并提交到远程仓库

    Docker将容器制作成镜像并提交到远程仓库 步骤如下 先在dockerhub上创建一个自己的用户https://hub.docker.com/.或者在阿里云也可以. 2. 然后先创建一个空的镜像名. ...

  5. C4.5决策树-为什么可以选用信息增益来选特征

    要理解信息增益,首先要明白熵是什么,开始很不理解熵,其实本质来看熵是一个度量值,这个值的大小能够很好的解释一些问题. 从二分类问题来看,可以看到,信息熵越是小的,说明分类越是偏斜(明确),可以理解为信 ...

  6. Yarn 容量调度器多队列提交案例

    目录 Yarn 容量调度器多队列提交案例 需求 配置多队列的容量调度器 1 修改如下配置 SecureCRT的上传和下载 2 上传到集群并分发 3 重启Yarn或yarn rmadmin -refre ...

  7. 日常Java 2021/10/17

    今天开始Javaweb编译环境调试,从tomcat容器开始,然后mysql的下载,连接工具datagrip,navicat for mysql,然后就是编写自己的sql,安装jdbc,eclipse连 ...

  8. A Child's History of England.1

    A Child's History of England, by Charles Dickens (狄更斯) CHAPTER I ANCIENT ENGLAND AND THE ROMANS If y ...

  9. MySQL(2):数据管理

    一. 外键概念: 如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键.由此可见,外键表示了两个关系之间的相关联系.以另一个关系的外键作主关键字的表被称为主表,具有此外键的表 ...

  10. entfrm开源免费模块化无代码开发平台,开放生态为您创造更多的价值

    entfrm开发平台6大特性,赋能快速开发,为您创造更多的价值: 1. 模块化 丰富的模块稳定的框架 后台极易上手 目前已包括系统管理.任务调度.运维监控.开发工具.消息系统.工作流引擎.内容管理等模 ...