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數組的數據被訂閱者消費,從而就可以調節生產者生產數據的速度