jdk9 響應式流

引用: https://www.cnblogs.com/IcanFixIt/p/7245377.html
引用: https://juejin.im/post/5e59bc266fb9a07ca90c2ecb

什麼是流

流是由生產者生產並由一個或多個消費者消費的元素(item)的序列。

這種生產者-消費者模型也被稱爲source/sink模型發佈者-訂閱者(publisher-subscriber )模型

流的處理機制

有幾種流處理機制,其中pull模型和push模型是最常見的。

  • push模型中,發佈者將元素推送給訂閱者。
  • pull模式中,訂閱者主動拉取發佈者生產的元素。

發佈者和訂閱者都以同樣的速率工作,這是一個理想的情況,這些模式非常有效。 但是,如果他們不按同樣的速率工作,這種情況下涉及的問題以及對應的解決辦法。
當發佈者比訂閱者快的時候

  • 一種解決方案是:後者必須有一個無邊界緩衝區來保存快速傳入的元素,或者它必須丟棄它無法處理的元素
  • 另一個解決方案是:使用一種稱爲背壓(backpressure )的策略。

背壓(back pressure)
 如果生產者發出的信息比消費者能夠處理消息最大量還要多,消費者可能會被迫一直在抓消息,耗費越來越多的資源,埋下潛在的崩潰風險。爲了防止這一點,需要有一種機制使消費者可以通知生產者,降低消息的生成速度。生產者可以採用多種策略來實現這一要求,這種機制稱爲背壓
 簡單來說:

  • 背壓指的發佈者和訂閱者之間的互動
  • 訂閱者可以告訴發佈者自己需要多少數據,可以調節數據流量,不會導致發佈者發佈數據過多導致數據浪費或壓垮訂閱者

響應式流

Reactive Stream 概念
 Reactive Stream (響應式流/反應流) 是JDK9引入的一套標準,是一套基於發佈/訂閱模式的數據處理規範。響應式流從2013年開始,作爲提供非阻塞背壓的異步流處理標準的倡議。它旨在解決處理元素流的問題——如何將元素流從發佈者傳遞到訂閱者,而不需要發佈者阻塞,或訂閱者有無限制的緩衝區丟棄
 更確切地說,Reactive流目的是“找到最小的一組接口,方法和協議,用來描述必要的操作和實體以實現這樣的目標:以非阻塞背壓方式實現數據的異步流”。

反應式流 (Reactive Stream) 規範誕生

Subscription 接口定義了連接發佈者和訂閱者的方法
Publisher<T> 接口定義了發佈者的方法
Subscriber<T> 接口定義了訂閱者的方法
Processor<T,R> 接口定義了處理器

Reactive Stream 規範誕生後,RxJava 從 RxJava 2 開始實現 Reactive Stream 規範 , 同時 Spring提供的Reactor 框架(WebFlux的基礎) 等也相繼實現了 Reactive Stream 規範

訂閱者和發佈者之間的交互
[圖片]

  • 發佈者(publisher)是潛在無限數量的有序元素的生產者。 它根據收到的要求向當前訂閱者發佈(或發送)元素。

  • 訂閱者(subscriber)從發佈者那裏訂閱並接收元素。

    • 發佈者向訂閱者發送訂閱令牌(subscription token)。
    • 訂閱者使用訂閱令牌從發佈者哪裏請求多個元素。
    • 當元素準備就緒時,發佈者向訂閱者發送多個或更少的元素。
    • 訂閱者使用訂閱令牌來調整請求數據的個數
  • 訂閱(subscription)表示訂閱者訂閱的一個發佈者的令牌。 當訂閱請求成功時,發佈者將其傳遞給訂閱者。 訂閱者使用訂閱令牌與發佈者進行交互,例如請求更多的元素(request)或取消訂閱(cancel)。
    -處理者(processor)充當訂閱者和發佈者的處理階段。 Processor接口繼承了Publisher和Subscriber接口。 它用於轉換發佈-訂閱者管道中的元素。 Processor<T,R> 訂閱類型T的數據元素,接收並轉換爲類型R的數據,併發布變換後的數據。 下圖顯示了處理者在發佈者——訂閱和管道中作爲轉換器的作用。 可以擁有多個處理者。
    在這裏插入圖片描述

JDK9 Flow API

JDK9中Reactive Stream的實現規範 通常被稱爲 Flow API ,通過java.util.concurrent.Flow 來實現響應式流.

APIs

//package java.util.concurrent;

public final class Flow {

    @FunctionalInterface
    public static interface Publisher<T> {       
     public void subscribe(Subscriber<? super T> subscriber);
    }

    public static interface Subscriber<T> {
       //發佈者subscribe訂閱者時觸發, 發送subscription
        public void onSubscribe(Subscription subscription);
		
		//訂閱者接收消息處理邏輯
        public void onNext(T item);
	   
        public void onError(Throwable throwable);
	
		//發佈者 close時觸發
        public void onComplete();
    }

 
    public static interface Subscription {
    	//訂閱者向發佈者請求數據
        public void request(long n);
        public void cancel();
    }
	
	//轉換器 分別繼承了 Subscriber和Publisher接口
    public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
    }
}

demo1

private static void test01() throws InterruptedException {
        Random random = new Random();
        //1.自定義發佈者, 發佈數據類型爲Integer
        //使用jdk9自帶的SubmissionPublisher,它實現了Publisher接口
        SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>();

        //2.定義訂閱者
        Flow.Subscriber<Integer> subscriber = new Flow.Subscriber<Integer>() {
            private Flow.Subscription subscription;

            @Override
            public void onSubscribe(Flow.Subscription sb) {
                //建立訂閱關係
                this.subscription = sb;

                //2. 請求數據 ----
                this.subscription.request(1);
            }

            @Override
            public void onNext(Integer item) {
                System.out.println("接收到數據:" + item);

                this.subscription.request(2);
                //已經達到了目標,調用cancel告訴發佈者,不在接收數據
//                this.subscription.cancel();
            }

            @Override
            public void onError(Throwable throwable) {
                //出現異常
                throwable.printStackTrace();

                this.subscription.cancel();
            }

            @Override
            public void onComplete() {
                //在publisher.close();時觸發..
                System.out.println("數據處理完了");
            }
        };

        // 3.發佈者和訂閱者 建立訂閱關係
        publisher.subscribe(subscriber);

        //4.生產數據,併發布
        publisher.submit(100);
        publisher.submit(200);
        publisher.submit(300);
        publisher.submit(400);

        //5.結束後,關閉發佈者
        publisher.close();

        Thread.currentThread().join(1000);
    }

demo2–Processor
Proceeor主要的作用是用具加工、處理髮布者發佈的消息。
下例:用來展示Processor過濾掉髮布者生產的小於200的消息,並且對消息進行轉換Integer --> String.
MyProcessor

static class MyProcessor extends SubmissionPublisher<String> implements Flow.Processor<Integer, String> {
        private Flow.Subscription subscription;
        @Override
        public void onSubscribe(Flow.Subscription sb) {
            //建立訂閱關係
            this.subscription = sb;
            //2. 請求數據 ----
            this.subscription.request(1);
        }

        @Override
        public void onNext(Integer item) {
            System.out.println("processor接收到數據:" + item);
			
			//過濾掉小於200的數據, 
            if(item > 200) {
            	//將消息轉換String
                this.submit("String MSG-" + item);
            }

            this.subscription.request(1);
        }

        @Override
        public void onError(Throwable throwable) {
            //出現異常
            throwable.printStackTrace();
            this.subscription.cancel();
        }

        @Override
        public void onComplete() {
            System.out.println("Processor:數據處理完了");
        }
    }

test-case

    private static void testProcessor() throws InterruptedException {
        Random random = new Random();
        //1.自定義發佈者, 發佈數據類型爲Integer
        SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>();

        // 2.定義處理器Processor
        MyProcessor processor = new MyProcessor();

        // 3.發佈者和Processor建立關係
        publisher.subscribe(processor);

        //4.定義訂閱者
        Flow.Subscriber<String> subscriber = new Flow.Subscriber<String>() {
            private Flow.Subscription subscription;

            @Override
            public void onSubscribe(Flow.Subscription sb) {
                //建立訂閱關係
                this.subscription = sb;

                //2. 請求數據 ----
                this.subscription.request(1);
            }

            @Override
            public void onNext(String item) {
                System.out.println("=============subscriber接收到數據:" + item);

                this.subscription.request(2);
                //已經達到了目標,調用cancel告訴發佈者,不在接收數據
//                this.subscription.cancel();
            }

            @Override
            public void onError(Throwable throwable) {
                //出現異常
                throwable.printStackTrace();

                this.subscription.cancel();
            }

            @Override
            public void onComplete() {
                //在publisher.close();時觸發..
                System.out.println("數據處理完了");
            }
        };

        //5. Processor同訂閱者建立關係
        processor.subscribe(subscriber);

        //4.生產數據,併發布
        publisher.submit(100);
        publisher.submit(200);
        publisher.submit(300);
        publisher.submit(400);

        //5.結束後,關閉發佈者
        publisher.close();

        Thread.currentThread().join(1000);
    }

執行結果:

processor接收到數據:100
processor接收到數據:200
processor接收到數據:300
processor接收到數據:400
Processor數據處理完了
=============subscriber接收到數據:String MSG-300
=============subscriber接收到數據:String MSG-400
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章