JDK9 Reactive Stream

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数组的数据被订阅者消费,从而就可以调节生产者生产数据的速度

猜你喜欢

转载自blog.csdn.net/qq_40378034/article/details/105598294