By default, code in RxJava is executed synchronously. This means that there is no concurrency and the code block is as follows:
Observable.just("One", "Two")
.doOnNext(i -> log("doOnNext", i))
.subscribe(i -> log("subscribe", i));
This will do the exact same thing as the following:
log("doOnNext", "One");
log("subscribe", "One");
log("doOnNext", "Two");
log("subscribe", "Two");
When the code is executed on different threads, something different happens. Two pieces of code can run simultaneously, but the steps of the flow that were defined while creating Observable will always be executed in the order they were defined.
Consider the following:
Observable.just("One", "Two")
.doOnNext(i -> log("doOnNext", i))
.observeOn(Schedulers.computation())
.subscribe(i -> log("subscribe", i));
Now, consider its output:
doOnNext:main:One
doOnNext:main:Two
subscribe:RxComputationThreadPool-1:One
subscribe:RxComputationThreadPool-1:Two
What happened here was that the main thread was quick to emit items, so it finished its work first and then the computation thread caught up. The items were processed in the order the steps were defined and the order they were emitted.
A very similar thing will happen with the following:
Observable.range(1, 1000)
.map(Object::toString)
.doOnNext(i -> log("doOnNext", i))
.observeOn(Schedulers.computation())
.subscribe(i -> log("subscribe", i));
The number 500 will never be printed before the number 499.
However, this is not what we always want. Sometimes, we want to just emit a bunch of values and let them complete in whatever order is the fastest.