I bet your RxJava is on the wrong thread

Dionysis Lorentzos
Dionysis’ desk
Published in
5 min readDec 4, 2018

4 years later of heavy usage and me naively thinking I know the ins and outs of RxJava, I was wrong.

When I thoroughly follow the requirements by CommitStrip

You know, it’s this feeling where you think you are doing fine and then you learn something and the whole world collapses bellow you. Pretty much that.

Today topic is threading and there are high chances you do it wrong as well because you think you know.

Regardless, let’s see some Rx puzzles and test how well you know subscribeOn and observeOn. You will find all the answers together at the bottom of the page.

Puzzle 1: Subject

For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: main
B. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: RxComputationScheduler
C. main thread name: main
subscribe onNext: main
subscribe onNext: main
D. None of the above

Puzzle 2: Subject with completable

Almost similar to the above. For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: RxIoScheduler
B. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: main
C. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: RxComputationScheduler
D. None of the above

Puzzle 3: Merge

For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: RxIoScheduler
B. main thread name: main
subscribe onNext: main
subscribe onNext: main
C. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: RxComputationScheduler
D. main thread name: main
subscribe onNext: RxIoScheduler
subscribe onNext: RxIoScheduler
E. None of the above

Puzzle 4: Merge with subject

Based on puzzles 2 & 3. For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: RxComputationScheduler
subscribe onNext: RxComputationScheduler
B. main thread name: main
subscribe onNext: RxComputationScheduler
subscribe onNext: RxComputationScheduler
subscribe onNext: main
C. None of the above

Puzzle 5: CombineLatest with observeOn

For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext: RxIoScheduler
B. main thread name: main
subscribe onNext: RxComputationScheduler
C. None of the above

Puzzle 6: CombineLatest with subscribeOn

For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext: RxIoScheduler
B. main thread name: main
subscribe onNext: RxComputationScheduler
C. Either of the aboveD. None of the above

Puzzle 7: Replay/RefCount with subscribeOn

For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext 1: RxComputationScheduler
subscribe onNext 2: RxComputationScheduler
B. main thread name: main
subscribe onNext 2: main
subscribe onNext 1: RxComputationScheduler
C. Either of the aboveE. None of the above, something else crazy

Puzzle 8: Completely messed up Replay/RefCount

For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext 1: RxNewThreadScheduler
subscribe onNext 2: RxNewThreadScheduler
subscribe onNext 3: RxNewThreadScheduler
B. main thread name: main
subscribe onNext 1: RxNewThreadScheduler
subscribe onNext 2: RxNewThreadScheduler
subscribe onNext 3: main
C. main thread name: main
subscribe onNext 1: RxNewThreadScheduler
subscribe onNext 2: RxComputationScheduler
subscribe onNext 3: main
D. All the aboveE. None of the above

Puzzle 9: Replay/RefCount with no completion and observeOn

For the given snippet:

Which do you think is the system output?

A. main thread name: main
subscribe onNext 1: main
subscribe onNext 2: main
B. main thread name: main
subscribe onNext 1: RxIoScheduler
subscribe onNext 2: RxIoScheduler
C. main thread name: main
subscribe onNext 1: RxIoScheduler
subscribe onNext 2: main
D. None of the above

Answers

If you don’t want spoilers, don’t scroll further.

Answer of puzzle 1

Correct answer is A because the default value is based on the subscribeOn (computation thread) and .onNext() of the subject is called from the main thread. Therefore the second emission will ignore the subscribeOn, change thread and will be emitted at the main thread.

Answer of puzzle 2

Correct answer is A. Same as puzzle 1. Default thread is computation but the .onNext() of the subject is now called from the io thread. Therefore the second emission will change thread and will be emitted at the io thread.

Answer of puzzle 3

Correct answer is A. The merge() by default will change its thread based on which thread was the last emitted value.

Answer of puzzle 4

Correct answer is B. The merge() by default will subscribe on the computation thread and then change its thread to the main because of the subject as explained in puzzle 2.

Answer of puzzle 5

Correct answer is B. The combineLatest() will emit a value based on the last emitted value’s thread. Therefore, the io thread, of the first leg, in that case is ignored and the value will be emitted at the computation thread of the second observable.

Note: the combining operation of the combine latest will also happen to the last emitted thread.

Answer of puzzle 6

Correct answer is C. This time, due to the subject, the emission sequence is not guaranteed. Therefore the emission can be either in io or computation thread.

Answer of puzzle 7

Correct answer is C. The emission sequence is not always guaranteed here. If both subscribers have subscribed, the emission will be on the computation scheduler affected by the first. If the second subscription subscribed and emitted faster, the first emission will be on main and then on computation.

Answer of puzzle 8

Correct answer is D. As above this comes to delicate timing issues which depend how fast the threads are. It could either emit all of them to a new thread, some of them to the new thread, or all of them to the initially “expected” threads.

Answer of puzzle 9

Correct answer is C. Although, you expect all the emissions to be in io thread, the replay will emit only the last value but will not repeat the last known thread. So the subscribing thread in the second case, which is the main, will also be the one where the 2nd value will be emitted.

Final thoughts

After all, looks like subscribeOn() is not as predictable and powerful. A proper way, to ensure an operation happens on a particular thread, is to fill your Rx pipeline with observeOn() especially on places after using a subject, a merge(), a combineLatest() or a refCount(). Being generous and put an extra “observeOn”s could be proven safer than not define a thread.

Keep Rx-ing. ✌️

Thank you for reading!

Want to learn more about me? I’m Dionysis, an Android dev at ShareNow + Founder of Nutech, a jobs app only for Android developers.

If you are an Android developer, you will most likely be interested in Nutech app.

--

--

Dionysis Lorentzos
Dionysis’ desk

Dionysis is an Android dev ShareNow + Founder of Nutech, a jobs app only for Android developers. He is passionate about auto industry innovation & space