前言:这个是JDK1.9的新特性,并且Reactive Stream和JDK1.8的Stream没有关联
Reactive Stream主要的操作类都是在
整体使用的设计模式是发布订阅的设计模式
java.util.concurrent.Flow 里面定义
Publisher接口是用来定义发布数据的(类似于RabbitMq的发布者)
subscribe方法用来连接Subscription(通道)
Subscriber接口是用来定义消费数据的(类似于RabbitMq的消费者)
onSubscribe方法用于接收Subscription
onNext方法用于接收数据
onError方法用于处理数据时候产生异常后接收异常
onComplete方法用于在发布者发布数据完成之后,也就是Publisher close之后,消费者就会调用到onComplete
接口Subscription(类似于RabbitMq的队列)
Subscription在发布者Publisher使用subscribe方法来和Subscriber制定关联关系的时候,Subscriber的onsubscribe方法就会接收Subscription的对象
request方法可以定义一次性消费的数量
request方法用于在消费者里面定义默认缓存265满了之后,所能消费的数量,消费不来,发布者就会在submit的时候阻塞,只有等消费之后,sumbit才会执行,再进行下一个submit。
cancel方法用于取消接收数据
接口Processor用于定义在Subscription过滤掉某些数据,onNext方法来过滤转发,最后转发到Subscriber
下面开始写例子
例子一
普通的Publisher到Subscriber
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
public class Test {
public static void main(String[] args) {
//1.定义发布者,使用SubmissionPublisher
SubmissionPublisher publisher=new SubmissionPublisher();
//2.定义消费者
Flow.Subscriber<Integer> subscriber=new Flow.Subscriber<Integer>() {
Flow.Subscription subscription=null;
//接收通道
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription=subscription;
this.subscription.request(1); //每次接收一条数据
}
//处理消息
@Override
public void onNext(Integer item) {
System.out.println("消费者消费消息:"+item);
this.subscription.request(1); //消费完再接收一条数据
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
//出异常之后可以让发布者不再发布消息
subscription.cancel();
}
@Override
public void onComplete() {
System.out.println("消息发布完成");
}
};
//3.发布者绑定消费者,其实中间会有个通道subscription
publisher.subscribe(subscriber);
//4.发送消息
int data=123;
publisher.submit(data);
// publisher.submit(321);
//5.发送完,关闭发布者
publisher.close();
//延迟主线程停止,否则没有消费消息就退出了
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
下面加多一行submit
int data=123;
publisher.submit(data);
publisher.submit(321);
运行结果
例子二
中间加了一个Processor,中转
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
public class Test2 {
public static void main(String[] args) {
//1.定义发布者,使用SubmissionPublisher
SubmissionPublisher publisher=new SubmissionPublisher();
//2.定义消费者
//改成 new 2.Integer改成String
Flow.Subscriber<String> subscriber=new Flow.Subscriber<String>() {
Flow.Subscription subscription=null;
//接收通道
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription=subscription;
this.subscription.request(1); //每次接收一条数据
}
//处理消息
@Override
public void onNext(String item) {
System.out.println("消费者消费消息:"+item);
this.subscription.request(1); //消费完再接收一条数据
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
//出异常之后可以让发布者不再发布消息
subscription.cancel();
}
@Override
public void onComplete() {
System.out.println("消费者onComplete:发布者消息发布完成");
}
};
//new 1.创建processor,并且publisher绑定processX
ProcessX processX=new ProcessX();
publisher.subscribe(processX);
//3.发布者绑定消费者,其实中间会有个通道subscription
// publisher.subscribe(subscriber);
//new 3.processX绑定subscriber
processX.subscribe(subscriber);
//4.发送消息
int data=123;
publisher.submit(data);
publisher.submit(321);
//5.发送完,关闭发布者
publisher.close();
//延迟主线程停止,否则没有消费消息就退出了
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ProcessX extends SubmissionPublisher<String> implements Flow.Processor<Integer,String>{
//一样需要拿到Subscription
Flow.Subscription subscription=null;
@Override
public void onSubscribe(Flow.Subscription subscription) {
//这里和消费者一致
this.subscription=subscription;
this.subscription.request(1);
}
@Override
public void onNext(Integer item) {
System.out.println("processor获取到的数据:"+item);
//如果数据大于123,就做转发,不大于123,就不转发,主要是过滤作用
if(item>123) {
this.submit("经过转发的数据:"+item);
}
this.subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
//如果出现异常就取消发布者发布消息
this.subscription.cancel();
}
@Override
public void onComplete() {
System.out.println("中转onComplete:发布者消息发布完成");
this.close();
}
}
运行结果
最后就是背压的概念:背压指的是消费者需要消费多少,生产者就生产多少数据
同时生产者生产的数据有一部分会到达消费者的缓冲区,如果超过256个,发布者的submit就会阻塞
例子三
缓冲区的256个数据
public class Test {
public static void main(String[] args) {
//1.定义发布者,使用SubmissionPublisher
SubmissionPublisher publisher=new SubmissionPublisher();
//2.定义消费者
Flow.Subscriber<Integer> subscriber=new Flow.Subscriber<Integer>() {
Flow.Subscription subscription=null;
//接收通道
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription=subscription;
this.subscription.request(1); //每次接收一条数据
}
//处理消息
@Override
public void onNext(Integer item) {
System.out.println("消费者消费消息:"+item);
System.out.println("停留3秒");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.subscription.request(1); //消费完再接收一条数据
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
//出异常之后可以让发布者不再发布消息
subscription.cancel();
}
@Override
public void onComplete() {
System.out.println("消息发布完成");
}
};
//3.发布者绑定消费者,其实中间会有个通道subscription
publisher.subscribe(subscriber);
//4.发送消息
// int data=123;
// publisher.submit(data);
// publisher.submit(321);
//new 1加上for循环,循环500个
for (int i=1;i<=500;i++){
System.out.println("发送数据:"+i);
publisher.submit(i);
}
//5.发送完,关闭发布者
publisher.close();
//延迟主线程停止,否则没有消费消息就退出了
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
缓冲区大小