The Future of Futures - A Talk About Java 8 CompletableFutures

Post on 15-Jan-2015

1,691 views 3 download

Tags:

description

This talk was given during the Java 8 Launch Event of the Israeli Java User Group (ilJUG) It is talking about Java8 CompletableFuture

transcript

ilJUG  Java  8  Launch  Event    The  Future  of  Futures  

(Apr  2014)  !

Haim Yadid - Performize-IT

About  Me:  Haim  Yadid

•21 Years of SW development experience •Performance Expert •Consulting R&D Groups •Training: Java Performance Optimization •Organizing : ILJUG

IL  JUG

•Israeli Java User Group •Reborn at 1/14 •Meetup : http://www.meetup.com/IL-JUG •G+: https://plus.google.com/u/0/communities/110138558454900054301

•Twitter: @il_jug

The  Beginning  of  Times

•Before J1.5 •Primitive life forms without Future •Threads •synchronization primitives •wait / notify •Most likely you will do it wrong

Futures  Introduction

•j.u.c.Future •introduced in JDK 1.5 •jsr166 (Doug Lea) •Together with Executors •And many other concurrency constructs •Part of the java.util.concurrent

What  is  a  Future

•A container for a result that will become available at a later time •Backed by a thread •May contain a Throwable if computation fails

What  is  a  Future

•Future means asynchronous •Future does not mean non blocking •Future does not mean reactive

The  ExecutorService

•Executor service is the container which handles a future •Has the threads which futures need. •Part of j.u.c (Executors.newXXX) •SingleThreadExecutor •FixedThreadPool •CachedThreadPool •ScheduledThreadPool

Simplest  Example

ExecutorService e = Executors.newSingleThreadExecutor();! Future<Integer> future = e.submit( () -> {sleep(1000);return 42;} ) ; // do something useful ? System.out.println(future.get());

Lambda  expression  which  represents  a  Callable<Integer>

User

Task(Callable,  Runnable)

Future

Executor

What  Else  Can  Be  Done?

•So we are blocked until future is finished •If it throw exception get will throw an exception •More that can be done: !

!

!

•And thats all !

future.cancel(false) ; // cancel future if not executed yet (in queue) future.cancel(true); // in addition interrupt the running task future.isCancelled(); // wether the future is cancelled. future.idDone() // whether the future is done.

Futures  Pros

•Futures combined with Callables are cheaper than threads. •Easier to maintain. •Async

We  will  get  to  the  cons…

Futures  Evolution  -­‐  Java  6

•Java 6 -jsr166x (CompletionService) •Separation of concerns

ExecutorService e = Executors.newFixedThreadPool(10);!CompletionService<Integer> completionService = new ExecutorCompletionService<>(e);! completionService.submit(() -> {sleep(1000); return 42;}) ;!Future<Integer> future = completionService.take();System.out.println(future.get()); // already completed…..

UserFuture

Executor ConsumerTask

Futures  Evolution  -­‐  Java  7

•Java7 - jsr166y (Fork Join Pools) •Has a common pool •ForkJoinTask extends Future •Completion ?

ForkJoinTask<Integer> task = ForkJoinPool.commonPool(). submit( () -> { sleep(1000); System.out.printf("done"); }); System.out.println(task.get());

complete()    a  Complete  mess

•With the method complete you can introduce a value before task competes. •But

ForkJoinTask<Integer> task = ForkJoinPool.commonPool(). submit(() -> { sleep(1000); return 42; }); ! sleep(10); task.complete(43); System.out.println(task.get()); task.complete(44); System.out.println(task.get()); sleep(2000); System.out.println(task.get());

43  

42  

44  

Nothing

•Dinosaurs are perfect •They are big •Powerful •State of the art

Nothing,  but  evolution  

Alternatives

•Akka Futures/Scala Futures •Scala Promises •Twitter - Finnagle •Guava ListenableFuture •Groovy Dataflow concurrency (GPars)

Proper  Completion

•A correct way to complete a future. •Once a future is completed it immutable •It is IMPORTANT

Data-­‐flow  Concurrency

•If we have variables that can be written to once •We have deterministic behaviour! •Run it a million times it will still work the same!!!

Composition

•Looking for websites that will interest a group of people

Get  Profile  On  linked  in  

user  1

Find  intersection  of  skills

Get  Profile  On  linked  in  

user  1

Get  Profile  On  linked  in  

user  n

search  on  google

Send  mail  with  group  recommendation

…….

 CompletableFuture  Is

•A container for a result that will become available at a later time •Backed by thread •May contain a Throwable if computation failed

CompletableFuture  Is

•Means asynchronous •Does not mean non blocking •Does not mean reactive

Is  Completable

•Is completed when completed! •The result can be set once. •Either by the task itself •Or from outside.

Is  Composable

•Composable •Lambda expression friendly •More functional in it’s nature

CompletableFuture  Creation

•supplyAsync •runAsync

import  java.util.concurrent.CompletableFuture;import  static  java.util.concurrent.CompletableFuture.*;

             CompletableFuture<Integer>  f  =  supplyAsync(                                  ()  -­‐>  {sleep(10000);return  42;}                );                  f.join();

Runs  on  ForkJoinPool.commonPool;  You  can  supply  an  executor  if  you  wantjoin  is  the  same  as  get  but  throws  an  

unchecked  exception  (hip  hip  hurray)

Construction

•new CompletableFuture(); •use complete(r) to complete it •use completeExceptionally(t) to complete with an exception

 CompletableFuture<Integer>  a=  new  CompletableFuture<>();

 a.complete(5);  a.completeExceptionally(new  IndexOutOfBoundsException());  

CompletableFuture

•Implements CompletableStage •A large set of methods (~60 •Every method is multiplied by three •XXXX(….) •XXXXAsync(…) •XXXX(….,Executor x)

Future  -­‐>  CompletableFuture

•Not really possible (Cleanly)

               Future<Integer>  future  =  ForkJoinPool.commonPool().submit(   ()  -­‐>  {sleep(4000);return  42;}                );!                CompletableFuture<Integer>  brighterFuture  =  supplyAsync(()  -­‐>  {                        try  {                                return  future.get();                        }  catch  (Exception  e1)  {                                throw  new  RuntimeException(e1);                        }                });                System.out.println(brighterFuture.get());

Nasty  Exception  handling  

Requires  another  thread….

!

thenApply

•Apply another action when result is available            

CompletableFuture<Integer>  f  =  supplyAsync(                        ()  -­‐>  {sleep(10000);return  42;});!CompletableFuture<Integer>  f2  =    f.thenApply((r)  -­‐>  r*r);

CompletableFuture<Integer>  f2  =    f.thenApplyAsync((r)  -­‐>  r*r);

CompletableFuture<Integer>  f2  =    f.thenApplyAsync((r)  -­‐>  r*r,                                                myLowPriorityExecutor);

Handling  Exceptions

•exceptionally()

CompletableFuture<Integer>  f  =  supplyAsync(                                ()  -­‐>  {sleep(10000);                                if  (true)  throw  new  RuntimeException();                                  return  42;});!CompletableFuture<Integer>  f2  =                          f.exceptionally((t)-­‐>  2).                            thenApply((r)  -­‐>  r*r);System.out.println(f2.get());

The  General  Case

•handle() - gets result and throwable manipulates them •whenComplete() - does something, pass result through

CompletableFuture<Integer>  f2  =  f.handle(                      (res,throwable)  -­‐>  (throwable==null)?  res*res  :  2);  !CompletableFuture<Integer>  f3  =  f.whenComplete(                              (res,  throwable)  -­‐>  {System.out.println("done");});

Composition

•thenCompose() •Performs another stage upon completion •On failure stage will not be performed

               CompletableFuture<Integer>  f1  =  supplyAsync(                                ()  -­‐>  {sleep(2100);return  42;});!                CompletableFuture<Integer>  f2  =  f1.thenCompose(                                (v)  -­‐>  supplyAsync(()  -­‐>  {sleep(2100);return  v+42;}))    ;                System.out.println(f2.get());

Combiners

•thenCombine() take both results and apply a function on them •thenAcceptBoth() - guess

               CompletableFuture<Integer>  f1  =  supplyAsync(                                ()  -­‐>  {sleep(2100);return  42;});                CompletableFuture<Integer>  f2  =  supplyAsync(                                ()  -­‐>  {sleep(2100);return  55;});!                CompletableFuture<Integer>  f3  =  f1.thenCombine(f2,                                (r1,r2)  -­‐>  r1+r2)    ;                  CompletableFuture<Void>  f4  =  f1.thenAcceptBoth(f2,                                (r1,  r2)  -­‐>  System.out.println(r1  +  r2))    ;                System.out.println(f3.get());

Either…

•thenApplyEither() take fastest result use it. Discard the second one •If exception is thrown behaviour is not predictable •Use case: parse fastest server result

               CompletableFuture<Integer>  f1  =  supplyAsync(                                ()  -­‐>  {sleep(2300);return  42;});                CompletableFuture<Integer>  f2  =  supplyAsync(                                ()  -­‐>  {sleep(2200);return  43;});!                CompletableFuture<Integer>  f3  =  f1.applyToEither(f2,(r)  -­‐>  r  *  r);

A  Better  Either

•Hold down exceptions letting other futures a chance to complete

 static<T>  CompletableFuture<T>  holdDownExceptionally(CompletableFuture<T>f,  CountDownLatch  latch)  {                  return  f.exceptionally((t)  -­‐>  {                                try  {                                        latch.countDown();latch.await();                                }  catch  (Exception  e)  {                                        throw  new  RuntimeException(t);                                }                                throw  new  RuntimeException(t);                          }).                            thenApply((r)  -­‐>  {latch.countDown();latch.countDown();return  r;});        }

A  Better  Either  cont

static  <T,U>  CompletableFuture<U>myApplytoEither(CompletableFuture<T>  f1,                                                                CompletableFuture<T>  f2,                                                              Function<?  super  T,  U>  fn)    {                  CountDownLatch  latch  =  new  CountDownLatch(2);                  CompletableFuture<T>  f1be  =  holdDownExceptionally(f1,latch);                CompletableFuture<T>  f2be  =  holdDownExceptionally(f2,latch);                  return  f1be.applyToEither(f2be,fn);}

How  Many?

•A completable future may have more than one dependents •Use getNumberOfDependents to get an estimate

CompletableFuture<Integer>  f  =  supplyAsync(                        ()  -­‐>  {sleep(10000);return  42;});!CompletableFuture<Integer>  f2  =    f.thenApply((r)  -­‐>  r*r);CompletableFuture<Integer>  f3  =    f.thenApply((r)  -­‐>  r*r*r);CompletableFuture<Integer>  f4  =    f.thenApply((r)  -­‐>  r*r*r*r);!f.getNumberOfDependents();      //  returns  3

Helper  Static  Functions

•allOf(CompletableFuture<?>... cfs) •no value returned

•anyOf(CompletableFuture<?>... cfs) •object retured

NIO  Non  blocking  IO

•Selectors •dispatchers •Reactor pattern •There is no support out of the box for CompletableFutures in NIO

What  about  J7  NIO2

•AsynchronousFileChannel •AsynchronousServerSocketChannel •Are using futures •Not adapted for completable futures.

AsynchronousFileChannel  afc  =                  AsynchronousFileChannel.open(Paths.get(“Video.avi"),                                StandardOpenOption.READ)      ;  ByteBuffer  r  =  ByteBuffer.allocate(500*1024*1024)  ;  Future<Integer>  a  =  afc.read(r,10*1024*1024);      //do  something  useful  while  waiting    a.get();      

Further  Info

•All examples can be found in github •https://github.com/lifey/compfut.git •Concurrency Interest Mailing List •Java Concurrency in Practice(Brian Goatz) •http://www.slideshare.net/kojilin/completable-future

Thanks + Q&A + Contact Me

© Copyright Performize-IT LTD.

http://il.linkedin.com/in/haimyadid

lifey@performize-it.com

www.performize-it.com

blog.performize-it.com

https://github.com/lifey

@lifeyx