RxJava的核心原理是不是這樣的?

        最近看到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

發佈了38 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章