1、概念
基于发布订阅者模式处理规范(机制),在JDK中真正叫法是FlowAPI
2、背压(backpress)
- 背压指的发布者和订阅者之间的互动
- 订阅者可以告诉发布者自己需要多少数据,可以调节数据流量,不会导致发布者发布数据过多导致数据浪费或压垮订阅者
3、Reactive Stream主要接口
java.util.concurrent.Flow
类中定义的接口:
1)、Publisher<T>
(发布者)
subscribe(Subscriber<? super T> subscriber)
:保证发布者和订阅者之间通过此方法建立订阅关系
2)、Subscriber<T>
(订阅者)
onSubscribe(Subscription subscription)
:第一此签署订阅关系,输入就是Subscription对象
onNext(T item)
:接收到一条数据
onError(Throwable throwable)
:数据出错
onComplete()
:数据处理完了
3)、Subscription
(发布者与订阅者之间的关系)
request(long n)
:告诉发布者需要多少资源
cancel()
:告诉发布者不再接收数据了
4)、Processor<T,R> extends Subscriber<T>, Publisher<R>
(既可以做消费者,又可以做发布者,承担中间角色)
4、案例
public class FlowDemo {
public static void main(String[] args) throws InterruptedException {
SubmissionPublisher<Integer> publisher = null;
try {
//定义发布者,发布的数据类型是Integer
//直接使用jdk自带的SubmissionPublisher,它实现了Publisher接口
publisher = new SubmissionPublisher<>();
//定义订阅者
Flow.Subscriber<Integer> subscriber = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
//保存订阅关系,需要用它来给发布者响应
this.subscription = subscription;
//请求一个数据
this.subscription.request(1);
}
@Override
public void onNext(Integer item) {
//接收一个数据并处理
System.out.println("接收到数据:" + item);
//处理完调用request再请求一个数据
this.subscription.request(1);
//或者 已经达到了目标,调用cancel告诉发布者不再接受数据了
//this.subscription.cancel();
}
@Override
public void onError(Throwable throwable) {
//出现了异常(例如处理数据的时候产生了异常)
throwable.printStackTrace();
//告诉发布者,后面不接收数据了
this.subscription.cancel();
}
@Override
public void onComplete() {
//全部数据处理完了(发布者关闭了)
System.out.println("处理完了!");
}
};
//发布者和订阅者之间建立订阅关系
publisher.subscribe(subscriber);
//发布数据
publisher.submit(100);
publisher.submit(101);
publisher.submit(102);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (publisher != null) {
//关闭发布者
publisher.close();
}
}
TimeUnit.SECONDS.sleep(1);
}
}
添加Processor中转站实例代码
/**
* Processor需要继承SubmissionPublisher并实现Processor接口
* 输入数据Integer,过滤小于0的,然后转换成字符串发布出去
*/
class MyProcessor extends SubmissionPublisher<String> implements Flow.Processor<Integer, String> {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
//保存订阅关系,需要用它来给发布者响应
this.subscription = subscription;
//请求一个数据
this.subscription.request(1);
}
@Override
public void onNext(Integer item) {
//接收一个数据并处理
System.out.println("处理器接收到数据:" + item);
//过滤掉小于0
if (item > 0) {
this.submit("转换后的数据:" + item);
}
//处理完调用request再请求一个数据
this.subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
//出现了异常(例如处理数据的时候产生了异常)
throwable.printStackTrace();
//告诉发布者,后面不接收数据了
this.subscription.cancel();
}
@Override
public void onComplete() {
//全部数据处理完了(发布者关闭了)
System.out.println("处理器处理完了!");
//关闭发布者
this.close();
}
}
public class FlowDemo2 {
public static void main(String[] args) throws InterruptedException {
SubmissionPublisher<Integer> publisher = null;
try {
//定义发布者,发布的数据类型是Integer
//直接使用jdk自带的SubmissionPublisher,它实现了Publisher接口
publisher = new SubmissionPublisher<>();
//定义处理器,对数据进行过滤
MyProcessor processor = new MyProcessor();
//定义订阅者
Flow.Subscriber<String> subscriber = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
//保存订阅关系,需要用它来给发布者响应
this.subscription = subscription;
//请求一个数据
this.subscription.request(1);
}
@Override
public void onNext(String item) {
//接收一个数据并处理
System.out.println("接收到数据:" + item);
//处理完调用request再请求一个数据
this.subscription.request(1);
//或者 已经达到了目标,调用cancel告诉发布者不再接受数据了
//this.subscription.cancel();
}
@Override
public void onError(Throwable throwable) {
//出现了异常(例如处理数据的时候产生了异常)
throwable.printStackTrace();
//告诉发布者,后面不接收数据了
this.subscription.cancel();
}
@Override
public void onComplete() {
//全部数据处理完了(发布者关闭了)
System.out.println("处理完了!");
}
};
//发布者和处理器建立订阅关系
publisher.subscribe(processor);
//处理器和最终订阅者建立订阅关系
processor.subscribe(subscriber);
//发布数据
publisher.submit(100);
publisher.submit(-100);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (publisher != null) {
//关闭发布者
publisher.close();
}
}
TimeUnit.SECONDS.sleep(1);
}
}
执行结果:
处理器接收到数据:100
处理器接收到数据:-100
处理器处理完了!
接收到数据:转换后的数据:100
处理完了!
5、实现原理
发布者发布的数据先存储在BufferedSubscription的array数组(相当于缓冲池,默认长度256)中,订阅者请求一个数据实际上请求的是存储在BufferedSubscription的array数组中的数据
发布者的submit(T item)
方法是一个阻塞方法,如果BufferedSubscription的array数组满了,submit(T item)
方法就会被阻塞,直到array数组的数据被订阅者消费,从而就可以调节生产者生产数据的速度