最近看到RxJava技術,好奇就網上找了些關於RxJava
的博文,但絕大部分文章都講了其使用,可我對最基本的東西——概念還是一臉懵逼。
這些文章看後,大概我知道兩個重點,一是類似於觀察者模式,二是任務執行與通知可以設置不同的線程。具體這個框架源碼怎麼做的就不知道了。看源碼太累了,很多有名的產品其實最核心的原理很簡單,demo也很好實現。比如dubbo,就是客戶端把調用方法與參數發過去,服務端根據invocation找到對應的service並執行,再把結果從遠程發過來;又比如druid,就是把sql包中的一切都適配一下,中間插入我要的filterChain,比如統計的filter。所以我就想先按自己的理解,寫幾行代碼,做一個小Demo實現兩個重點,請大家看看是不是這樣的原理。
核心業務:我作爲觀察者,註冊到你這裏,你就開始處理(我是參數)並把結果通知我,我接着處理。當然你處理和我處理都可以封成runnable扔到不同的線程池中。
與一般觀察者模式不同的是,被觀察者什麼時候開始處理不知道(也許是被其它調用,也許是監聽到什麼,也許...),而這裏是觀察者註冊的那一時刻。
操作符:我作爲觀察者,操作符會造成你被一個新產生的中間人代理了。這時我註冊到中間人,中間人開始處理(我是參數)併產生一箇中間觀察者註冊到你這裏,你處理後,結果給中間觀察者處理,中間觀察者處理後,再給我(參數)處理。
話不多說,上代碼(不包含操作符):
package com.rxjava.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* 學習rxjava的原理
*
* 【思考】: 如果作爲框架,call函數功能也應該從外部提供,用內部類?用abstract方法?
* 如果call可給其它線程執行用哪個方案?用內部類?
*
* @author ACER
* @date 2019年11月24日
*/
public class RxjavaTest {
// 配置用其它線程執行時,訂閱者的操作在這裏執行
private static ExecutorService ioExecutor;
private static final AtomicLong threadIndex = new AtomicLong(0);// 線程計數
private static int cupNum = Runtime.getRuntime().availableProcessors();// cpu數
static {
System.out.println("cpu:" + cupNum);
ioExecutor = new ThreadPoolExecutor(cupNum, cupNum, 1000 * 60,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(100),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "io_thread_"
+ threadIndex.incrementAndGet());
return thread;
}
});
}
public static void main(String[] args) {
RxjavaTest test = new RxjavaTest();
test.regListen(new Listenner() {
@Override
public void OnNext(int plusValue) {
System.out.println("copy that!!!->" + plusValue);
}
});
System.out.println("---------------【修改爲不同的線程執行】------------------");
test.useSameThread = false;
test.regListen(new Listenner() {
@Override
public void OnNext(int plusValue) {
System.out.println("copy that in anather thread!!!->"
+ plusValue);
}
});
}
public boolean useSameThread = true;// 是否用同一線程
public Listenner _listenner;// 註冊進來的訂閱者
// 註冊操作。同時就調用執行相關服務,執行過程中會通知訂閱者。
void regListen(Listenner li) {
_listenner = li;
// 有人註冊了,開始工作
if (_listenner != null) {
call(_listenner);
}
}
// 真正的服務過程(其實也可以給其它線程去運行)
public void call(Listenner listenner) {
int a = 4;
int b = 6;
if (useSameThread) {
listenner.OnNext(a + b);
b = 45;
listenner.OnNext(a + b);
} else {
// 後面扔到線程池執行
final int result = a + b + 100;
ioExecutor.submit(new listenRun(listenner, result));
final int result2 = a + b + 1000;
ioExecutor.submit(new listenRun(listenner, result2));
}
}
//配置其它線程時:訂閱者執行用其它線程,產生的Runnable對象。
public class listenRun implements Runnable {
public Listenner lisInner;
private int resultInner;
public listenRun(Listenner a, int b) {
lisInner = a;
resultInner = b;
}
@Override
public void run() {
System.out
.println("ThreadName:" + Thread.currentThread().getName());
lisInner.OnNext(resultInner);
}
}
// 訂閱者應實現的接口
public static interface Listenner {
void OnNext(int plusValue);
}
}
這是執行結果:
cpu:4
copy that!!!->10
copy that!!!->49
---------------【修改爲不同的線程執行】------------------
ThreadName:io_thread_1
ThreadName:io_thread_2
copy that in anather thread!!!->110
copy that in anather thread!!!->1010
當然上面的代碼如果把call過程也配置一下,放入另外的線程池就更好了。最後再改造成一個框架,從外部傳入call的操作就更完善了。
歡迎大家指點一下,謝謝!
注:剛看到這個文章,寫的不錯。https://blog.csdn.net/TellH/article/details/71534704