Java 8 concurrency abstractions

Preview:

Citation preview

Java 8 Concurrency Abstractions

-Exploring Java 8 concurrency abstractions

-Comparing against Java 7 concurrency abstractions

Agenda

1. Overview of concurrency libraries added in JDK82. Asynchronous result processing3. CompletableFuture (Vs classical Future)4. StampedLock (Vs ReadWriteLock)

? Pre-requisites: Assumes Lambda, Method Ref,. Functional Interfaces (Supplier, Consumer, Function etc)

Myself

• GlobalLogic India Ltd, Bangalore• Concurrency Enthusiast (Golang, Java)• Servlet 4.0 Spec (JSR 369), JavaEE8• JavaCodeGeeks• Dzone

1. Concurrency Overview

– Adders And Accumulators– New Methods to ConcurrentHashMap– Common Pool

Asynchronous Result Processing

1. Overview of concurrency libraries added in JDK8

2. Asynchronous result processing3. CompletableFuture (Vs classical Future)4. StampedLock (Vs ReadWriteLock)

Asynchronous Result Processing– Synchronous– Not Synchronous, Asynchronous [Java 5]– Asynchronous and Reactive [Java 8]

Client Server

Request

Server Proc...

Client Blocked

Response

Synchronous

Client Server

Request

Server Proc...

Ctrl ret. immed

Asynchronous

Client polls - X

Client polls - Y

Response

Client ServerRequest

Server Proc...

Response Push

Ctrl ret. immed

Asynchronous + Reactive

Agenda

1. Overview of concurrency libraries added in JDK8

2. Asynchronous result processing3. CompletableFuture (Vs classical Future)4. StampedLock (Vs ReadWriteLock)

Classical Future

• An interface in java.util.concurrent pkg• FutureTask is the concrete implementation• Represents the result of an async processing.• Utility Methods with the interface:– isDone()– isCancelled()– cancel(boolean mayInterruptIfRunning)

• Lets see it in action!

Classical Future continued 3• Future programming model: ExecutorService pool = ... Future<Double> bankBalance=pool.submit(()->{

Thread.sleep(5000L);//sim processing time return bankBalance; });

try{ double balance = bankBalance.get(); //blocking call }catch(InterruptedException

ignore){}

• Work around:– May spin around and check with isDone() or isCancelled();– Use CompletableFuture!

CompletableFuture

• A class in java.util.concurrent package• Implements CompletionStage and Future

interfaces (both in java.util.concurrent pkgs)• Since CompletableFuture implements Future,

it can be used classically – blockingly!• CompletionStage is the interface which

provides all the reactive constructs; fat interface

CompletableFuture Reactive Usage

• CompletableFuture Programming Model.• Get a CompletableFuture instance:– Static Factory

• CompletableFuture.supplyAsync(Supplier) //one variant• CompletableFuture<Double>bankBalanceFut =

CompletableFuture.supplyAsync(()->{return getBankBalance(); //long running task

}) //args Supplier instance.

• Wire reactions:• bankBalanceFut.thenAccept((balance)->{ //three variants; System.out.println(“Available balance: ”+balance) }) //args Consumer inst.

• Lets try this!

supplyAsync(...) Variants• publicstatic <U> CompletableFuture<U> supplyAsync(

Supplier<U> supplier)– Uses ForkJoinPool.commonPool();

• publicstatic <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)– Uses the passed into Executor as the thread pool

• supplyAsync’s counterpart – runAsync(...) – Takes Runnable instead of Supplier– Returns CompletableFuture<Void> – Calling get() would return null

thenAccept(...) Variants• public CompletableFuture<Void> thenAccept(Consumer<?

super T> action)

• public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)

• public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)

More into piping Reactions

• Fluent API helps piping reactions.• supplyAsync(Supplier)

.whenComplete(BiConsumer)//res, err .thenApply(Function)

.thenAccept(Consumer) .thenRun(Runnable)

Other Important Piping APIs - 1

• Composition: public <U> CompletableFuture<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)

(This) CompletionStage<U>

Function(? super T, ? extends

CompletionStage<U>)CompletionStage<T>

Other Important Piping APIs - 2

• Combination: public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)

(This) CompletionStage

<U>

(Other) CompletionStage

<V>

BiFunction(? super T, ? Super U, ? extends V)

CompletionStage<T>

How we leveraged the power of CompletableFuture

• Use Case #1 (Remote Serivces)– Two remote services.– Both replicate service– We needed anyone to respond; faster! (acceptEither)– Lets simulate what we did!– Can be extended easily to any number of services!

• public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)

How we leveraged the power of CompletableFuture - 2

• Use Case #2 (update UI after File FTP completes)– Application UI uploads file; not on UI thread;– UI thread is not blocked; it reacts whenever FTP is completed.– CompletableFuture<FTPStatus> ftp = CompletableFuture.supplyAsync(()->{

return FTPClient.uploadFile(file);});

ftp . whenComplete((ftpStatus,error)->{ //takes BiConsumer; alt. handle takes //BiFunctionif (error == null){

//grab UI thread and update of successful FTP} else{

// grab UI thread and update of failure FTP}

})

Creating APIs to return CompletableFuture

• How to expose CompletableFuture APIs for Clients!• Instantiate CompletableFuture• Set result to it asynchronously.

public CompletableFuture<String> getPageContent(URL url){CompletableFuture<String> futurePage = CompletableFuture<>();Runnable task = ()->{ try{String htmlContent = fetchPageContent(url); //long runningfuturePage.complete(htmlContent); //not with classicFuture

// this is why it is CompletableFut. }catch(Throwable th){

futurePage.completeExceptionally(th); //set complete exceptionally }};

exec.submit(task); return futurePage; }

Exception Handling

• Exception Handling in CompletableFuture:– exceptionally()– handle()– whenComplete()

• Time for Code !

ReentrantReadWriteLock Precursor to StampedLock

• java.util.concurrent.locks.ReentrantReadWriteLock– Pessimistic Write– Pessimistic Read– No Optimistic Locking

ReentrantReadWriteLock • ReentrantReadWriteLock Usage: private SomeClass theData;

pri final ReadWriteLock myLocks =new ReentrantReadWriteLock(true);

public void write(){myLocks.writeLock().lock();try{theData.write();}finally{myLocks.writeLock().unlock();}}

public void read(){myLocks.readLock().lock();try{theData.read();}finally{myLocks.readLock().unlock();}}

StampedLock

• JDK8 addition into package java.util.concurrent.locks– Works with versions of StampedLock – the

“Stamp” – Modes• Pessimistic Write• Pessimistic Read• Optimistic Read! (Optimization)

Pessimistic StampedLocking Pessimistic Usage:private SomeClass theData;

private final StampedLock lock=new StampedLock(true);

public void write(){long stamp = lock.writeLock();try{theData.write();}finally{lock.writeLock(stamp);}}

public void read(){long stamp = lock.readLock();try{theData.read();}finally{lock.unlockRead(stamp);}}

Optimistic StampedLockOptimistic usage:• try OptimisticRead• Validate optimisticRead stamp• Based on the validation take further action.• Lets Try!!!

private int p1, p2StampedLock lock = new StampedLock();public void read(){ long stamp = lock.tryOptimisticRead(); int l1 = p1; int l2 = p2;if(lock.validate(stamp)){ //validate the stamp (version) process(l1, l2);}else{stamp = lock.readLock()//acquire pessimistic lockstry{l1 = p1; l2= p2; process(l1, l2); }finally{lock.unlockRead(stamp)}}}

Conclusion

• CompletableFuture is powerful– Explore more– Write your own RxJava

• StampedLock is more efficient and optimized for particular use cases!

Thank You for your

Patience!

Recommended