This document discusses asynchronous and synchronous programming in Java. It covers several key aspects:
1. Java supports both multi-threading for synchronous programming as well as asynchronous programming using non-blocking I/O and libraries like RxJava.
2. Asynchronous programming can be difficult due to issues like complex error handling, lack of readability, and difficulty debugging.
3. Many open-source libraries have been created to help with asynchronous programming using approaches like futures, callbacks, and promises.
4. Reactive programming libraries like RxJava, Reactor, and Vert.x use approaches like asynchronous streams to simplify asynchronous code.
4. Where’s the problem
with async programming?
HARD TO DESIGN
HARD TO DEVELOP
HARD TO HANDLE ERRORS
HARD TO READ CODE
HARD TO DEBUG
HARD TO TEST
HARD TO PROFILE
HARD TO VISUALIZE
HARD TO DOCUMENT
5. Open Source Community does not sleep
ParSeq
RxJavaVertX
Reactor
Guava
Akka
...and much more...
7. Why not Futures?
Java Futures are straight-forward to use for a single level of asynchronous
execution but they start to add non-trivial complexity when
they're nested (prior to Java 8 CompletableFuture).
Conditional asynchronous execution flows become difficult to optimally
compose (particularly as latencies of each request vary at runtime) using
Futures. It can be done of course, but it quickly becomes complicated (and thus
error prone) or prematurely blocks on 'Future.get()', eliminating the benefit of
asynchronous execution.
Source:
Ben Christensen http://techblog.netflix.com/2013/02/rxjava-netflix-api.html
8. Callbacks
Simple Theory:
Task A -> Task B -> Task C
Real Implementation:
TaskC = ...
TaskB = ...
TaskA = ...
TaskA.start(
TaskB.start(
TaskC.start()
)
) Pyramid of Doom
12. What’s in JavaScript ?
No multithreading, but can work asynchronously
e.g. AJAX requests
Asynchronous events are based callbacks
jQuery provides promises & deferred (not good implementation)
Standard interoperable Promise A+: https://promisesaplus.com/
Multiple implementations
13. Promise
listener for success event
listener for failure event
listener for done event (both success and failure)
allows to specify next Promise (ability to build a chain of Promises)
! watch out for fluent chaining A.then(B).then(C)
it may be A->B->C or A->[B,C] depending on implementation
Implementations:
JDeferred - https://github.com/jdeferred/jdeferred (based on jQuery)
RxJava Promises - https://github.com/darylteo/rxjava-promises (based on Promise A+)
14. Promise + Deferred
Promise begin() {
Deffered deferred = ...
startAsync(
aresult -> {
if (aresult.failure()) deferred.failure();
else deferred.success();
}
);
return deferred.promise();
}
Promise promise = begin();
promise.done( ... );
promise.fail( ... );
promise.always( ... );
promise.then( doNext );
CLIENT
or use Java 8 CompletableFuture instead if you don’t like Deferred concept
[EXAMPLE CODE]
15. Reactor
“On a recent laptop with a dual-core processor,
it's possible to process over 15,000,000 events per second with the
RingBufferDispatcher and over 25,000,000 events per second in a single thread.”
reactor.on(Selectors.object("test"), new Consumer<Event<String>>() {
@Override
public void accept(Event<String> ev) {
log.info("Received event with data: " + ev.getData());
}
});
reactor.notify("test", Event.wrap("BLABLA"));
[EXAMPLE CODE]
16. ParSeq
Parallelization of asynchronous operations (such as IO)
Serialized execution for non-blocking computation
Code reuse via task composition
Simple error propagation and recovery
Execution tracing and visualization
https://github.com/linkedin/parseq
17. ParSeq (2)
final Task<String> googleContentType = getContentType("http://www.google.com");
final Task<String> bingContentType = getContentType("http://www.bing.com");
final Task<String> contentTypes =
Task.par(googleContentType, bingContentType)
.map("concatenate", (google, bing) -> "Google: " + google + "n" + "Bing: " + bing + "n");
privateTask<String> getContentType(String url) {
return HttpClient.get(url).task()
.map("getContentType", response -> response.getContentType());
}
[EXAMPLE CODE]
19. Akka
http://akka.io/
Actor Model
multiple actors
supervisors
Hello Librarian!
Have you read
“Java in 1 minute
for dummies“ ?
Yes, sure.
I’m too lazy to read it.
Could you summarize
this book for me?
No problem.
System.out.println(“Hello World”);
Now you know Java.
[EXAMPLE CODE]
21. Vert.x
Simple concurrency model. All code is single threaded, freeing from
the hassle of multi-threaded programming.
Asynchronous programming model for writing truly scalable non-
blocking applications.
Distributed event bus that spans the client and server side. The event
bus even penetrates into in-browser JavaScript allowing to create so-
called real-time web applications.
23. Copying streams
byte[] buf = new byte[4096];
while (true) {
int r = inputStream.read(buf);
if (r == -1) break;
outputStream.write(buf, 0, r);
}
Plain Old Java way Vert.x async way
Pump.createPump(input, output)
.start();
or
req.response()
.sendFile("webroot/" + file);
ALL IN JAVA CODE
processing every 4KB!
MOSTLY HANDLED BY JVM AND OS
no blocking threads
Apache Commons IOUtils.copy()
Guava ByteStreams.copy()
24. WARNING!
Using Event-loop
for long synchronous processing will lead to:
For long processing
use dedicated workers
outside main event-loop.
VERY SLOW QUEUE
25. Reactive Streams
http://ww.reactive-streams.org/
https://github.com/reactive-streams/reactive-streams-jvm/
Akka
Ratpack
Reactive Rabbit
Reactor
RxJava
Slick
Vertx 3
public interface Publisher<T> {
public void subscribe(Subscriber<? superT> s);
}
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
public interface Subscription {
public void request(long n);
public void cancel();
}
backpressure
handling
26. Reactive Manifesto
Responsive: The system responds in a timely manner if at all possible. (...)
Resilient: The system stays responsive in the face of failure. (...)
Elastic/Scalable: The system stays responsive under varying workload. (...)
Message Driven: (...) asynchronous message-passing to establish a boundary
between components that ensures loose coupling, isolation, location
transparency, and provides the means to delegate errors as messages. (...)
http://www.reactivemanifesto.org/
29. Scaling
Scale UP (vertical)
adding more resources on single machine (CPU, memory, disk space...)
Scale OUT (horizontal)
adding more machines
requires shared contract and serializable messages
Look for async-supporting libraries/frameworks that allows
not only vertical scaling but also helps with horizontal scaling.
Examples: Akka, Hazelcast, Vert.x, Atmosphere...