Tuesday, 30 September 2014

An Asynchronous World

This article aims to spot a light on asynchronous data processing in the Java world. But let's at first talk a bit about the difference between synchronous and asynchronous operation execution.

A synchronous execution means that you perform an operation on the client side by then waiting until the result is returned by the server. The sends are in sync with the retrievals and so the execution of multiple operations is in sequence. This means that the client side execution is blocked until the operation returns. 

An asynchronous execution, on the other hands side, means that the client is just performing operation calls (requests) to the server by not waiting for the immediate result. The client is not blocked and just continues to perform operations calls. Therefore the result which is returned by the server has to be handled as soon as it arrives at the client side. The order in which the results are arriving may not be the same as the order of the original requests. The function which is handling this 'in the future' arriving result is normally named a Callback Function.

Several programming languages (and more specific the frameworks those are related to them) have this concept implemented. E.G: Java has 'Futures' and AngularJs (an MVC framework from the Java Script world) has 'Promises'.

Let's focus on Java for now. So let's at first take a look on 'Futures'.

'java.util.concurrent.Future' is an interface which provides the following methods:

  • Future<V>
    • V get() - Waits for the result by blocking until the result arrives
    • V get(long timeout, TimeUnit unit) - Waits for max. the provided timeout
    • boolean isDone() - Checks if the work is done (or was interrupted)
    • boolean cancel(boolean mayInteruptIfRunning) - cancels the work
    • boolean isCancelled() - Was it cancelled?
So a Future is the result of an asynchronous computation which gives you the ability to check the state of the computation and to get the result of the execution (in the future).

BTW: Futures are used in the Java world related to multi threaded execution. Work is submitted to an ExecuterService. A thread pool can be used to paralyze the workload. Because one thread may be faster than another one, the result may not be returned in the same order as submitted. This means that the result is returned asynchronously.

If you use Couchbase's earlier Java Client (1.4.x), then you will realize that an asynchronous operation will return you a Future object.

Furthermore it is extending an 'AbstractListenableFuture' which allows you to attach a listener (similar to a Callback Function) to the operation.

OK, so this is how things are working with the Couchbase 1.4.x Java Client. Things are becoming even cooler with the new 2.x version because the new Java Client uses ReactiveX for Java (http://reactivex.io). So let's start to talk a bit what ReactiveX is and which pattern can be implemented by using it.

The ReactiveX website says: "ReactiveX - The Observer pattern done right; ReactiveX is a combination of the best ideas from the Observer pattern, the Iterator pattern, and functional programming."

  • In the Observer pattern, Observers are used to observe a subject (Observable). The Observers are realizing (signaled by the Observable) if the state of the Observable is changing by being able to react on such an event. It's easy to see that you can use it also for asynchronous data access. 
  • The Iterator pattern allows to iterate through a collection of objects without the need to know the internal structure of the collection of objects. To combine the Observer pattern with the Iterator pattern means that you can receive a data stream (instead the whole collection of data) by then reacting on the arrival of new data items. 
  • The functional aspect is that you may pass functions (E.G. as anonymous classes or lambda expressions) as the arguments to an Observable.

In JavaRx, such an Observable object can be used in a similar way as a Java Iterable (E.G. using methods like 'skip', 'map', 'forEach'). The difference is that you just consume data from an Iterable (pull access) but you also produce (push access) data regarding an Observable. There are two new methods available for an Observable:
  • onCompleted() - An Observable calls it's observer's onCompleteMethod()
  • onError() - An Observable calls it's observer's onError() method if an error occurred
Here an example how you can interact with an Observable:

So let's finish this article by showing how Observables are used in the new 2.x Couchbase Java Client:

A more advanced example can be found in Michael's blog post about the new Couchbase Java SDK or in Phil's demo application.