RxJava Reactive Streams

Introduction to Reactive Streams

Before we talk about what RxJava is and fully understand it we must first comprehend some concepts and principles that are behind the creation of the API. In reality, RxJava is just part of a broader project called ActiveX which applies the concepts that will be explained here not only for Java but also to other platforms such as Python, Go, Groovy, C#, and many others. It is worth mentioning that ActiveX is not the only one to implement these ideas. Spring Boot Framework also has its own implementation and is called Spring WebFlux (result of the Spring Project Reactor).

Reactive Stream is an initiative to provide a standard for asynchronous stream processing with non-blocking backpressure.

— reactive-streams.org

RxJava as well as WebFlux are implementations of the Reactive Streams. But what exactly does this statement above mean? Traditional methods when called normally get blocked until it finishes whatever it needs to do. If the method is doing only mathematical calculations or checking some logic out of their arguments the non-blocking nature of the asynchronous stream processing will not make much difference, but if we start talking about accessing the file system, save a file to some device, read information from service, or communicate to a microservice remotely that is when things start to get interesting.

A scenario particularly interesting for Reactive Streams is in a microservices environments such as cloud environments. In such architectures we have many services talking to each other and every time this communication takes place the service that initiated it will need to wait for some time until it takes some action. On top of that, the agent providing the service usually does not respond to a single client but to multiple ones. It is in this sequence of events that Reactive Streams excel!

Reactive Streams solves the problem effectively by using something called Event Loop. Every time a new request comes to the Reactive Streams the thread used by the method does not get blocked. Just after it executes the request it goes and does something else, it does not wait. Only when request is done the Event Loop adds to the queue this new event and the next available thread is processed which means, no wasted resources! The usage time of every thread is used to the fullest.

Fig. 1 – Reactive Event Loop

The no-reactive method needs to instantiate a new thread every time a new request is made which means that if you have too many simultaneous requests you can end up with multiple threads sitting there just waiting, doing nothing and consuming resources.

Last but not least, reactive streams must support backpressure. This means that the receiver (Subscriber) of a reactive stream can control the number of events it is able to process. This is useful in cases where the sender (Publisher) produces more events than the receiver can handle, and backpressure is a mechanism to allow the sender to slow down the event generation in order to allow the receiver properly to process them.

Reactive Streams can be considered an evolution of the well-known observer pattern plus the addition of functional paradigm bringing to the mix a very powerful API. This API allows for the creation of a chain of methods bringing a very declarative style of programming as well as abstracting out low-level threading, synchronization, thread-safety, concurrent data structures, etc.

Reactive Reference Implementation

As mentioned, it is not only the ReactiveX project, more specifically RxJava, that implements the Reactive Streams standards which means that you are going to find similar structures and elements in different projects although using distinct names depending on each project.

At a very high level every Reactive Stream implementation has a Publisher,  the entity that produces the data to be consumed by a Subscriber.  Another important architectural element is the Subscription. The Subscription represents the message control link between Publishes and Subscribers itself by which it gives the Subscriber the capability to inform the Publisher how much data it can handle, in other words the entity that makes backpressure possible. In addition to that, between Publisher and Subscriber, we normally also have a chain of functions, known as function chain. It is through this chain of functions where all sorts of operations are applied over the streams such as Map, Filter, FlatMap, and many more.

Fig. 2 – Reactive Streams Base Classes

Keep in mind that Reactive Streams has its style on the bases of the Functional Paradigm, and therefore, having the knowledge of concepts such as immutability, pure functions, high-order functions, etc., is essential to fully understand the RxJava and properly use its API.

Some RxJava Code at Last

I know there is a lot of information to absorb before the first lines of code, but trust me, what I presented before will save you from a lot of trouble when developing a Reactive Functional Programming API such as  RxJava.

Hello World

package rxjava.examples;

import io.reactivex.rxjava3.core.*;

public class HelloWorld {
    public static void main(String[] args) {
        Flowable.just("Hello world").subscribe(System.out::println);
    }
}

Looking at this simple hello-world code might seem odd for someone used to working with traditional Object-oriented programming (OOP) only, but now that we have set the scene for the Reactive Functional Programming on the previous sections it will be much easier to understand what is going on here.

The first thing to note is the use of the Class Flowable. It is important to remember that here everything is a constant infinite flow of data or stream, and the Flowable class represents exactly that. Even to print a single String you need to somehow provide it through a stream. In such cases, Flowable gives the just method that gives an Observable object with just one item. You can think of Observable as a Publisher class mentioned before. This means that you need to subscribe to a Subscriber to read what is coming from the streamer. Here the subscriber simply prints out whatever is coming from the stream.

This API has much more power and flexibility than shown in this simple hello-world example, but it is when dealing with millions of data that Reactive Streams approach really shines.

Of course, there is a lot more to talk about regarding RxJava I have barely scratched the surface here. Apart from Flowable and Observable base classes there are also Single, Completable and Maybe base classes to deal with more specific situations that I haven’t even touched on here in this article.

Talking about everything RxJava is able to do would take many more pages, not a simple article like this one. The goal here is to just give a high-level overview of RxJava, the main concepts behind any Reactive Streams application as well as about Reactive Functional Programming paradigm.

Final Thoughts

I hope to further explore the RXJava API but this article explains the basics for any Reactive Stream which should enable the reader to quickly understand any implementation of the Reactive Streams.

Also, this article does not present examples on how powerful Reactive Streams standard is over the traditional blocking approach. To give the readers of this article an insight of its power I conducted a small experiment where I implemented a very simple REST service using Reactive Streams versus a traditional blocking one, and the result was pretty impressive.

For closure, I will leave the reader to take their own conclusions based on the result graphics of this experiment:

Fig. 3 – Traditional Blocking API Results

Fig. 4 – Reactive Streams API Results

Written by Berchris Requiao.