Rxjava2-執行緒切換解析

檸檬茶就是力量發表於2019-07-23

這篇文章來總結一下Rxjava中切換執行緒的內在是怎麼實現的

ObservableOn()

直接檢視實現,會發現onSubscribe()中做了一些判斷,比如82 104等幾行都是做了一些同步 非同步 等的判斷,然後初始化DisposableonSubscribe()是上游Observable完成了整條訂閱鏈之後呼叫的,所以這些操作是在開始訂閱之後才初始化操作,然後106行可以看出把一個包裝處理過的Disposable傳遞給下游

image.png


和之前的一樣,subscribeActual方法裡會將observer進行包裝,然後傳遞給source也就是上游進行訂閱
* `40`行進行了判斷所傳進來的`scheduler`是否跟原本的執行緒一致,如果是一樣的就直接傳遞不用進行處理
*  `43`行建立了一個對應`scheduler`的`worker`,`worker`在後續負責把資料在對應的執行緒進行發射操作
複製程式碼

image.png

發射資料onNext處理
        @Override
        public void onNext(T t) {
          ...
          // 前面的都先忽略掉,會發現最後會呼叫這個方法
            schedule();
        }
        
      void schedule() {
         if (getAndIncrement() == 0) {
         // 在這個可以看到,上面根據schedule的worker執行了schedule(),並且把自身傳進去,this其實實現了runnable,所以可以理解為傳了一個runnable進去
            worker.schedule(this);
        }
    }
複製程式碼
接著上面的以AndroidSchedulers.mainThread()這個scheduler為例,這裡實際上是將主執行緒的looper傳進去了

image.png

檢視一下這個scheduler的worker,會發現worker的基類schedule()方法是相同的互相呼叫的,所以可以直接看多個引數的schedule(),可以看到73行建立了一個ScheduledRunnable物件,並且把主執行緒的handler以及外面的Observer傳遞過去,接著82行用主執行緒的handler傳送訊息,119ScheduledRunnable裡的run被呼叫,接著Observer也就是runnable也呼叫run方法

image.png

image.png

到這裡可以看出,實際上當切換執行緒的時候,observer(也實現了Runnable)的onNext往scheduler裡傳送自身,讓scheduler來決定自身應該在什麼執行緒執行run方法,接下來看回observer的run方法,就是判斷了一下要執行哪個方法

image.png

可以看到最後是呼叫了onNext方法,到這裡就完成了指定執行緒發射資料的功能
        void drainNormal() {
            int missed = 1;

            final SimpleQueue<T> q = queue;
            final Observer<? super T> a = downstream;

            for (;;) {
                if (checkTerminated(done, q.isEmpty(), a)) {
                    return;
                }

                for (;;) {
                    boolean d = done;
                    T v;

                    try {
                        v = q.poll();
                    } catch (Throwable ex) {
                        Exceptions.throwIfFatal(ex);
                        disposed = true;
                        upstream.dispose();
                        q.clear();
                        a.onError(ex);
                        worker.dispose();
                        return;
                    }
                    boolean empty = v == null;

                    if (checkTerminated(d, empty, a)) {
                        return;
                    }

                    if (empty) {
                        break;
                    }

                    a.onNext(v);
                }

                missed = addAndGet(-missed);
                if (missed == 0) {
                    break;
                }
            }
        }

複製程式碼
值得注意的是可以看到的是v也就是我們要發射的資料,是通過poll方法獲取的,檢視程式碼可以發現

queue實際上就是一個Disposable也就是說是上游Observable,通過上游的poll方法去獲取要onNext的資料

image.png

檢視Observable其中一個實現ObservableMap的poll方法,可以看到這裡實際上也是呼叫上游的poll方法,並且對資料的格式也就是不允許為null做了一層判斷
        public U poll() throws Exception {
            T t = qd.poll();
            return t != null ? ObjectHelper.<U>requireNonNull(mapper.apply(t), "The mapper function returned a null value.") : null;
        }
複製程式碼
poll方法操作的物件實際上是下圖104行的時候new出來的,具體檢視其實就是快取資料,類似一個容量池的作用

image.png

用一段虛擬碼來展示切換執行緒之後的observer,其實相當於onNext等方法都被放在指定的執行緒裡去發射資料
public class Observer {
    Observer oldObserver;

    public Observer(Observer observer) {
        oldObserver = observer;
    }

    public void onNext(T t) {
        // 一些其他操作
        new Thread("Android mainThread") {
            @Override
            public void run() {
                oldObserver.onNext(t);
            }
        } .start();
    }

    public void onError(Throwable e) {
        // 一些其他操作
        new Thread("Android mainThread") {
            @Override
            public void run() {
                oldObserver.onError(e);
            }
        } .start();
    }

    public void onComplete() {
        // 一些其他操作
        new Thread("Android mainThread") {
            @Override
            public void run() {
                oldObserver.onComplete();
            }
        } .start();
    }
}
複製程式碼

相關文章