Java 8 concurrency abstractions

27
Java 8 Concurrency Abstractions -Exploring Java 8 concurrency abstractions -Comparing against Java 7 concurrency abstractions

Transcript of Java 8 concurrency abstractions

Page 1: Java 8 concurrency abstractions

Java 8 Concurrency Abstractions

-Exploring Java 8 concurrency abstractions

-Comparing against Java 7 concurrency abstractions

Page 2: Java 8 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)

Page 3: Java 8 concurrency abstractions

Myself

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

Page 4: Java 8 concurrency abstractions

1. Concurrency Overview

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

Page 5: Java 8 concurrency abstractions

Asynchronous Result Processing

1. Overview of concurrency libraries added in JDK8

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

Page 6: Java 8 concurrency abstractions

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

Page 7: Java 8 concurrency abstractions

Agenda

1. Overview of concurrency libraries added in JDK8

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

Page 8: Java 8 concurrency abstractions

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!

Page 9: Java 8 concurrency abstractions

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!

Page 10: Java 8 concurrency abstractions

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

Page 11: Java 8 concurrency abstractions

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!

Page 12: Java 8 concurrency abstractions

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

Page 13: Java 8 concurrency abstractions

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)

Page 14: Java 8 concurrency abstractions

More into piping Reactions

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

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

.thenAccept(Consumer) .thenRun(Runnable)

Page 15: Java 8 concurrency abstractions

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>

Page 16: Java 8 concurrency abstractions

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>

Page 17: Java 8 concurrency abstractions

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)

Page 18: Java 8 concurrency abstractions

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}

})

Page 19: Java 8 concurrency abstractions

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; }

Page 20: Java 8 concurrency abstractions

Exception Handling

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

• Time for Code !

Page 21: Java 8 concurrency abstractions

ReentrantReadWriteLock Precursor to StampedLock

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

Page 22: Java 8 concurrency abstractions

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();}}

Page 23: Java 8 concurrency abstractions

StampedLock

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

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

Page 24: Java 8 concurrency abstractions

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);}}

Page 25: Java 8 concurrency abstractions

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)}}}

Page 26: Java 8 concurrency abstractions

Conclusion

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

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

Page 27: Java 8 concurrency abstractions

Thank You for your

Patience!