RxJava Source Parsing 05-Thread Switching

Keywords: Java Android

RxJava Source Parsing 05-Thread Switching

In this article, we will analyze the switching of Rx Java threads.

Observable.just("123")
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.newThread())
    .subscribe(new Subscriber<String>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(String s) {

        }
    });   

subscribeOn

The observaOn acts on the operator until a new observeOn operator appears and switches when Observer.onNext, onCompleted, and onError occur. subscribeOn can switch multiple times.

subscribeOn

SubscribeOn acts on the Observable creation operator and the doOnSubscribe operator before the operator. When subscribeOn has more than one, only the first one is valid (except doSubscriber, doSubscribe is called before OnSubscribe.call).

Switch on Onsubscribe.call()  

subscribeOn source code parsing

public final Observable<T> subscribeOn(Scheduler scheduler, boolean requestOn) {
    if (this instanceof ScalarSynchronousObservable) {
        return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler);
    }
    return unsafeCreate(new OperatorSubscribeOn<T>(this, scheduler, requestOn));
}

Look at Operator Subscribe On

@Override
public void call(final Subscriber<? super T> subscriber) {
    final Worker inner = scheduler.createWorker();

    SubscribeOnSubscriber<T> parent = new SubscribeOnSubscriber<T>(subscriber, requestOn, inner, source);
    subscriber.add(parent);
    subscriber.add(inner);

    inner.schedule(parent);
}  

Schduler. createWorker () is called here; Worker is created and schedule is called. This scheduler is passed in by the constructor, which is the parameter passed in by calling subscribeOn().

Take a look at Schedulers.newThread(), and trace the source code to find that it's the NewThreadScheduler class.

public final class NewThreadScheduler extends Scheduler {
    private final ThreadFactory threadFactory;

    public NewThreadScheduler(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    @Override
    public Worker createWorker() {
        return new NewThreadWorker(threadFactory);
    }
}  

Mainly from NewThreadWorker

public NewThreadWorker(ThreadFactory threadFactory) {
    ScheduledExecutorService exec = Executors.newScheduledThreadPool(1, threadFactory);

    boolean cancelSupported = tryEnableCancelPolicy(exec);
    if (!cancelSupported && exec instanceof ScheduledThreadPoolExecutor) {
        registerExecutor((ScheduledThreadPoolExecutor)exec);
    }
    executor = exec;
}  

You can see that the thread pool is created here, and then look at the scheme method.

@Override
public Subscription schedule(final Action0 action, long delayTime, TimeUnit unit) {
    if (isUnsubscribed) {
        return Subscriptions.unsubscribed();
    }
    return scheduleActual(action, delayTime, unit);
}  

public ScheduledAction scheduleActual(final Action0 action, long delayTime, TimeUnit unit) {
    Action0 decoratedAction = RxJavaHooks.onScheduledAction(action);
    ScheduledAction run = new ScheduledAction(decoratedAction);
    Future<?> f;
    if (delayTime <= 0) {
        f = executor.submit(run);
    } else {
        f = executor.schedule(run, delayTime, unit);
    }
    run.add(f);

    return run;
}  

You can see that executor.submit() is called here. action is the parent object passed in by Operator SubscribeOn. schedule, which is a subclass of Action0 and eventually calls parent.call. Parent is SubscribeOn Subscriber

@Override
public void call() {
    //...
    src.unsafeSubscribe(this); //src is subscribe
}  

Thus onNext, onCompleted and onError are already executed in the switched threads, thus realizing the switching of threads.

@Override
public void onNext(T t) {
    actual.onNext(t);
}

@Override
public void onError(Throwable e) {
    try {
        actual.onError(e);
    } finally {
        worker.unsubscribe();
    }
}

@Override
public void onCompleted() {
    try {
        actual.onCompleted();
    } finally {
        worker.unsubscribe();
    }
}  

ObeOn Source Code Analysis

After some methods, Observer#observeOn() is called.

public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
    //...
    return lift(new OperatorObserveOn<T>(scheduler, delayError, bufferSize));
}  

The lift method converts the incoming T to R, where Operator ObserveOn inherits from Operator

summary

RxJava's thread switching is actually based on Scheduler generated by Schedulers, and ultimately calls the corresponding thread pool for thread switching.

If it's Android Schedulers. mainThread, it uses Handler to switch to the main thread.

class LooperScheduler extends Scheduler {
    //...       

    @Override
    public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {
        if (unsubscribed) {
            return Subscriptions.unsubscribed();
        }

        action = hook.onSchedule(action);

        ScheduledAction scheduledAction = new ScheduledAction(action, handler);

        Message message = Message.obtain(handler, scheduledAction);
        message.obj = this; // Used as token for unsubscription operation.

        handler.sendMessageDelayed(message, unit.toMillis(delayTime));

        if (unsubscribed) {
            handler.removeCallbacks(scheduledAction);
            return Subscriptions.unsubscribed();
        }

        return scheduledAction;
    }

    //...
}

Posted by bobthedog on Sat, 25 May 2019 11:16:22 -0700