My task was pretty simple. I had two long long running blocks of code which I put into separate functions called processData1() and processData2() . None of the functions return any value. I wanted to execute them on separate background threads in parallel and notify when they both complete or at least one of it fails.

The first step would be to wrap the functions into Completables using Completable.fromAction() method. Completable emits either an exception or completes when the task is finished so it‘s perfect for wrapping functions which don’t return any value.

Merging it together

To execute both Completables in parallel they have to be merged using (not surprisingly) merge operator.

Merge combines multiple Observables (or in that case Completables) into one by merging their emissions like shown on the diagram:

For two completables the diagram can be simplified since completable doesn’t emit any value. In that case, merge function creates a new completable instance which completes when both completables completes or emits an error.

simplified marble diagram for merge operator of two completables

Specify the scheduler

To execute the tasks on a separate thread it’s convenient to use subscribeOn function which allows specifying Scheduler on which a Completable will operate. I passed Schedulers.io() scheduler so both actions will be executed on the thread from the IO pool.

Resulting code (with a bug 🐛)

The resulting code is really simple and looks like this:

As I mentioned earlier that code has a subtle bug in it. If you run that code with some prints you’ll see that both tasks are executed on the thread from IO pool but they’re both executed on the same thread.

The reason is really simple: mergeWith function combines two completables into one and returns a new Completable instance which subscribes to both completables. The scheduler won’t be applied to each of the completables but only to completable returned by merge.

Corrected version

To both tasks work in parallel subscribeOn should be called on each of the completables that would be merged.

And the output finally is correct, both tasks run in parallel on the separate thread from the io pool.

What about other operators?

The same rule applies not only to the merge operator but also to zip operator which you can use to run a code from two Singles or Observables in parallel and combine their results.

Code for parallel execution of two zipped Singles which emit some Strings would look like this:

My other posts about RxJava: