2. About myself
• Solutions Architect at Farata Systems
• Java Champion
• Latest book:
“Angular 2 Development with TypeScript”
3. “If I had asked people what they wanted,
they would have said faster horses”
Henry Ford
4. Synchronous vs asynchronous
• Synchronous programming is straightforward
• Asynchronous programming dramatically increases complexity
5. Challenges in async programming
• Handling failed async requests
• Chaining async calls
• The user already closed the view
• Switching threads to update UI
6. and more challenges
• Avoiding writing blocking code in a multi-threaded app
• Several consumers
• Composable functions
• Killing a pending Http request
8. Examples of backpressure
• The stock price changes 100 times a second
• Accelerometer produces 50 signals a second
• Iteration through a JDBC result set (rxjava-jdbc; rxjava2-jdbc)
• A user drags the mouse to draw a curve. Can’t apply back pressure.
9. Reactive Apps
• The data is processed as streams
• Message-driven: notifications
• Resilient: stay alive in case of failures
• Data flows through your app’s algorithms
• Hide complexity of multi-threading
10. Reactive Streams
• A spec for async stream processing with non-blocking backpressure
http://www.reactive-streams.org
• Reactive Streams interfaces for JVM
https://github.com/reactive-streams/reactive-streams-jvm
• Reactive Streams-based products:
RxJava2, Java 9 Flow APIs, Reactor 3, Akka Stream, MongoDB, Vert.x …
15. Main RxJava2 players
• Observable or Flowable - producers of data
• Observer or Subscriber - consumers of data
• Subject or Processor - implements both producer and consumer
• Operator - en-route data transformation
• Scheduler - multi-threading support
16. Main Publishers and Subscribers in RxJava2
Observable
no backpressure support
public interface Observer<T> {
void onSubscribe(Disposable var1);
void onNext(T var1);
void onError(Throwable var1);
void onComplete();
}
Publisher Subscriber
Not from
Reactive Streams
17. Observable
no backpressure support
Flowable
with backpressure support
public interface Observer<T> {
void onSubscribe(Disposable var1);
void onNext(T var1);
void onError(Throwable var1);
void onComplete();
}
public interface Subscriber<T> {
void onSubscribe(Subscription var1);
void onNext(T var1);
void onError(Throwable var1);
void onComplete();
}
Not from
Reactive Streams
From
Reactive Streams
Main publishers and subscribers in RxJava2
Publisher Subscriber
18. Creating an Observable
• Observable.create()
• Observable.fromArray()
• Observable.fromIterable()
• Observable.fromCallable()
• Observable.fromFuture()
• Observable.range()
• Observable.just()
Observable.create(subscriber -> {
int totalBeers = beerStock.size();
for (int i = 0; i < totalBeers; i++) {
// synchronous push
subscriber.onNext(beerStock.get(i));
}
subscriber.onComplete();
});
19. Observable<Beer> observableBeer = Observable.create(/* data source */);
observableBeer
.skip(1)
.take(3)
.filter(beer -> "USA".equals(beer.country))
.map(beer -> beer.name + ": $" + beer.price)
.subscribe(
beer -> System.out.println(beer),
err -> System.out.println(err),
() -> System.out.println("Streaming is complete”),
disposable -> System.out.println(
"Someone just subscribed to the beer stream!!!”)
);
);
Observable push
O
b
s
e
r
v
e
r
Subscription
20. Creating an Observer and subscribing
Observable<Beer> beerData = BeerServer.getData(); // returns an Observable
Observer beerObserver = new Observer<Beer>() {
public void onSubscribe(Disposable d) {
System.out.println( " !!! Someone just subscribed to the bear stream!!! ");
// If the subscriber is less than 21 year old, cancel subscription
// d.dispose();
}
public void onNext(Beer beer) {
System.out.println(beer);
}
public void onError(Throwable throwable) {
System.err.println("In Observer.onError(): " + throwable.getMessage());
}
public void onComplete() {
System.out.println("*** The stream is over ***");
}
};
beerData
.subscribe(beerObserver); // Streaming starts here
21. Subscription subscription = Observable.create(new Observable.OnSubscribe<Response>() {
OkHttpClient client = new OkHttpClient();
@Override
public void call(Subscriber<? super Response> subscriber) { // invoked on subscription
try {
Response response = client.newCall( // prepare the call for future execution
new Request.Builder().url(“http://localhost:8080/beers“)
.build())
.execute(); // use enqueue() for async requests
subscriber.onNext(response);
subscriber.onComplete();
if (!response.isSuccessful()) {
subscriber.onError(new Exception(“Can’t get beers”));
}
} catch (IOException e) {
subscriber.onError(e);
}
}
})
.subscribe(...); // pass Observer; use observeOn/SubscribeOn to switch threads
Pushing HTTP responses
https://square.github.io/okhttp
31. An Operator
Observable Observable
A transforming
function
observableBeer
.filter(b -> "USA".equals(b.country))
Docs: http://reactivex.io/documentation/operators
32. QUIZ: What value(s) this observable emits?
Observable
.just(5, 9, 10) // emits 5, 9, 10
.filter(i -> i % 3 > 0)
.map(n -> "$" + n * 10)
.filter(s -> s.length() < 4);
43. Turning a cold observable into hot
ConnectableObservable<Long> numbers = (ConnectableObservable<Long>) Observable
.interval(1, TimeUnit.SECONDS) // generate seq numbers every second
.publish(); // make it hot
numbers.connect(); // creates an internal subscriber to start producing data
numbers.subscribe(n ->System.out.println("First subscriber: "+ n ));
Thread.sleep(3000);
numbers.subscribe(n ->System.out.println(" Second subscriber: "+ n ));
46. Concurrency with Schedulers
• subscribeOn(strategy) - run Observable in a separate thread:
Operations with side effects like files I/O;
Don’t hold off the UI thread
• observeOn(strategy) - run Observer in a separate thread,
Update Swing UI on the Event Dispatch Thread
Update Android UI on the Main thread
47. Multi-threading strategies
• Schedulers.computation() - for computations: # of threads <= # of cores
• Schedulers.io() - for long running communications; backed by a thread pool
• Schedulers.newThread() - new thread for each unit of work
• Schedulers.from(Executor) - a wrapper for Java Executor
• Schedulers.trampoline() - queues the work on the current thread
• AndroidSchedulers.mainThread() - handle data on the main thread (RxAndroid)
49. Multi-threaded processing with flatMap()
Operator1() Operator2() flatMap()
Observable
Subscriber
Thread 1
Observable/Thr2
Observable/Thr3
Observable/ThrN
Spawn a separate thread for each observable
…
50. Turning a value into
an observable
Observable.range(1, 1000)
.flatMap(n->Observable.just(n)
.subscribeOn(Schedulers.computation()))
.map(n->n*2)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(myView.update());
Subscribing to each
observable on the
computation thread
Switching to the
main thread
Updating the UI
52. Parallel operations with ParallelFlowabe
• Parallel execution of some operators
• The source sequence is dispatched into N parallel “rails”
• runOn() —-> sequential() is more efficient fork/join than flatMap()
• Each rail can spawn multiple async threads with Schedulers
53. Parallel Execution
int numberOfRails = 4; // can query #processors with parallelism()
ParallelFlowable
.from(Flowable.range(1, 10), numberOfRails)
.runOn(Schedulers.computation())
.map(i -> i * i)
.filter(i -> i % 3 == 0)
.sequential()
.subscribe(System.out::println);
Tasks run simultaneously on different CPUs or computers.
ParallelFlowableRange.java
54. Summary
• Observable: no backpressure support
• Flowable: backpressure support
• Operators can be chained
• flatmap() used for handling observable of observables
• Schedulers support multi-threading
• subscribeOn()/observeOn() - switching between threads
• ParallelFlowable - initiate parallel processing