The Future of Futures - A Talk About Java 8 CompletableFutures

7,311 views
7,000 views

Published on

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

2 Comments
15 Likes
Statistics
Notes
No Downloads
Views
Total views
7,311
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
95
Comments
2
Likes
15
Embeds 0
No embeds

No notes for slide

The Future of Futures - A Talk About Java 8 CompletableFutures

  1. 1. ilJUG  Java  8  Launch  Event     The  Future  of  Futures   (Apr  2014)   ! Haim Yadid - Performize-IT
  2. 2. About  Me:  Haim  Yadid •21 Years of SW development experience •Performance Expert •Consulting R&D Groups •Training: Java Performance Optimization •Organizing : ILJUG
  3. 3. 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
  4. 4. The  Beginning  of  Times •Before J1.5 •Primitive life forms without Future •Threads •synchronization primitives •wait / notify •Most likely you will do it wrong
  5. 5. 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
  6. 6. 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
  7. 7. What  is  a  Future •Future means asynchronous •Future does not mean non blocking •Future does not mean reactive
  8. 8. 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
  9. 9. 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
  10. 10. 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.
  11. 11. Futures  Pros •Futures combined with Callables are cheaper than threads. •Easier to maintain. •Async We  will  get  to  the  cons…
  12. 12. 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….. User Future Executor Consumer Task
  13. 13. 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());
  14. 14. 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  
  15. 15. Nothing •Dinosaurs are perfect •They are big •Powerful •State of the art Nothing,  but  evolution  
  16. 16. Alternatives •Akka Futures/Scala Futures •Scala Promises •Twitter - Finnagle •Guava ListenableFuture •Groovy Dataflow concurrency (GPars)
  17. 17. Proper  Completion •A correct way to complete a future. •Once a future is completed it immutable •It is IMPORTANT
  18. 18. 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!!!
  19. 19. 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 …….
  20. 20.  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
  21. 21. CompletableFuture  Is •Means asynchronous •Does not mean non blocking •Does not mean reactive
  22. 22. Is  Completable •Is completed when completed! •The result can be set once. •Either by the task itself •Or from outside.
  23. 23. Is  Composable •Composable •Lambda expression friendly •More functional in it’s nature
  24. 24. 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)
  25. 25. 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());  
  26. 26. CompletableFuture •Implements CompletableStage •A large set of methods (~60 •Every method is multiplied by three •XXXX(….) •XXXXAsync(…) •XXXX(….,Executor x)
  27. 27. 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….
  28. 28. !
  29. 29. 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);
  30. 30. 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());
  31. 31. 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");});
  32. 32. 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());
  33. 33. 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());
  34. 34. 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);
  35. 35. 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;});
        }
  36. 36. 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);
 }
  37. 37. 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
  38. 38. Helper  Static  Functions •allOf(CompletableFuture<?>... cfs) •no value returned •anyOf(CompletableFuture<?>... cfs) •object retured
  39. 39. NIO  Non  blocking  IO •Selectors •dispatchers •Reactor pattern •There is no support out of the box for CompletableFutures in NIO
  40. 40. 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();      
  41. 41. 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
  42. 42. 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

×