CompletableFuture уже здесь Дмитрий Чуйко dmitry.chuyko@oracle.com c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ Содержание Введение API Накладные расходы Пример. Rest-сервис c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 2/39 Safe Harbor Statement The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 3/39 Введение c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 4/39 Параллелизм в Java: История ∙ Threads – Monitors – Locks and other primitives ∙ Executors – Runnable<T>, Callable<T> → lambdas ∙ ∙ ∙ ∙ Future<T> ForkJoinPool stream.parallel() Explicit → implicit c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 5/39 Параллелизм в Java: Future<T> ∙ ∙ Обёртка для результата, доступного в будущем Получение значения требует проверки исключений – ExecutionException содержит исходное unchecked исключение ∙ ∙ ∙ Исполняется в каком-то потоке и блокирует какой-то (другой) поток Можно проверить, доступно ли уже значение Можно отменить вычисление Future f = executor . submit (() -> ...); result = f . get (); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 6/39 Сложности: Обработка ошибок try { try { return parse ( fileObject , content . get ()); } catch ( E x e c u t i o n E x c e p t i o n e ) { unfold ( e ); } } catch ( IOException e ) { log . error (e , fileObject ); } catch ( I n t e r r u p t e d E x c e p t i o n e ) { throw new R u n t i m e E x c e p t i o n ( e ); } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 7/39 Сложности: Обработка ошибок private static void unfold ( E x e c u t i o n E x c e p t i o n e ) throws IOException , InterruptedException { Throwable cause = e . getCause (); if ( cause instanceof E x e c u t i o n E x c e p t i o n ) unfold (( E x e c u t i o n E x c e p t i o n ) cause ); if ( cause instanceof IOException ) throw ( IOException ) cause ; if ( cause instanceof I n t e r r u p t e d E x c e p t i o n ) throw ( I n t e r r u p t e d E x c e p t i o n ) cause ; if ( cause instanceof Error ) throw ( Error ) cause ; if ( cause instanceof R u n t i m e E x c e p t i o n ) throw ( R u n t i m e E x c e p t i o n ) cause ; throw new R u n t i m e E x c e p t i o n ( e ); } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 8/39 Сложности: Давайте добавим обработчики! readFileAsync ( file , content -> System . out . println ( content ); ex -> ex . p ri n tS ta c kT r ac e (); ); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 9/39 Сложности: Давайте добавим обработчики! readFileAsync ( file , content -> System . out . println ( content ); ex -> ex . p ri n tS ta c kT r ac e (); ); ∙ ↓Добро пожаловать сюда↓ http://callbackhell.com/ readFileAsync ( file , content -> p r o c e s s C o n t e n t A s y n c ( content , c -> System . out . println ( c ) , e -> e . p r in tS t ac kT r ac e () ); ex -> ex . p ri n tS ta c kT r ac e (); ); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 9/39 CompletableFuture: Боремся с вложенностью C o m p l e ta b l e F u t u r e . supplyAsync (() -> readFile ( file )) . t he n C o m p o s e A s y n c ( content -> p rocess Conten t ( content )) . whenComplete (( result , ex ) -> { if ( ex == null ) { System . out . println ( result ); } else { ex . pr in t St ac k Tr ac e (); } }); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 10/39 CompletableFuture: Композиция ∙ Method chaining – Нет блокирующих вызовов – Знакомо и удобно (builders, mocks, streams) ∙ Работаем с несколькими CF c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 11/39 API c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 12/39 Что за класс: CompletableFuture<T> ∙ ∙ ∙ Core library class since Java SE 8 implements Future<T> implements CompletionStage<T> – – – – – Элемент композиции Вычисление функции Связь через результаты Методы преобразований toCompletableFuture() c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 13/39 Методы: Создание ∙ CompletableFuture() – boolean complete(T value), успешно только для одного потока ∙ ∙ ∙ ∙ static <U> CompletableFuture<U> completedFuture(U value) static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier[, Executor executor]) static CompletableFuture<Void> runAsync(Runnable runnable[, Executor executor]) ForkJoinPool.commonPool() по умолчанию c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 14/39 Методы: Создание CompletableFuture < Long > cf1 = C o m p l e t a b l e F u t u r e . supplyAsync (() -> 42 L ); CompletableFuture < Long > start = C o m p l e t a b l e F u t u r e . c o mp le t ed Fu t ur e (42 L ); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 15/39 Методы: *Отступление Упрощённая запись generics ∙ ∙ Function<? super T,? extends U> → Function<T,U> Consumer<? super T> → Consumer<T> c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 16/39 Методы: Трансформации ∙ <U> CompletableFuture<U> thenApply(Function<T,U> fn) – Нет "Async"→ продолжаем в том же потоке ∙ <U> CompletableFuture<U> thenApplyAsync(Function<T,U> fn [, Executor executor]) c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 17/39 Методы: Трансформации (map) CompletableFuture < Long > cf2 = C o m p l e t a b l e F u t u r e . supplyAsync (() -> 42 L ) . thenApply ( r1 -> r1 + 2015); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 18/39 Методы: Подписка ∙ ∙ ∙ CompletableFuture<Void> thenAccept(Consumer<T> block); CompletableFuture<Void> thenRun(Runnable action); Async versions CompletableFuture < Void > cf3 = C o m p l e t a b l e F u t u r e . supplyAsync (() -> 42 L ) . thenApply ( r1 -> r1 + 2015) . thenAccept ( System . out :: println ); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 19/39 Методы: Обработка ошибок ∙ ∙ ∙ CompletableFuture<T> exceptionally(Function<Throwable, T> fn) CompletableFuture<U> handle(BiFunction<T, Throwable, U> fn) Ошибка пробрасывается по цепочкам C o m p l e ta b l e F u t u r e . supplyAsync (() -> readFile ( file )) . t he n C o m p o s e A s y n c ( content -> p rocess Conten t ( content )) . thenAccept ( System . out :: println ) . exceptionally ( Throwable :: p ri nt S ta ck T ra ce ); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 20/39 Методы: Комбинация (reduce) ∙ <U,V> CompletableFuture<V> thenCombine (CompletionStage<U> other, BiFunction<T,U,V> fn) CompletableFuture < Long > cf2 = C o m p l e t a b l e F u t u r e . supplyAsync (() -> 42 L ) . thenCombine ( C o m p l e t a b l e F u t u r e . supplyAsync (() -> 2015) , Math :: min ); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 21/39 Методы: Для набора ∙ ∙ CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 22/39 Методы: Композиция (flatMap) ∙ CompletableFuture<U> thenCompose(Function<T,CompletableFuture<U>> fn) CompletableFuture < Long > cff = C o m p l e t a b l e F u t u r e . supplyAsync (() -> 42 L ) . thenCompose ( x -> C o m p l e t a b l e F u t u r e . supplyAsync (() -> x + 2015)); CompletableFuture < CompletableFuture < Long > > cff = C o m p l e t a b l e F u t u r e . supplyAsync (() -> 42 L ) . thenApply ( x -> C o m p l e t a b l e F u t u r e . supplyAsync (() -> x + 2015)); c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 23/39 Методы: Get ∙ ∙ ∙ ∙ T get() throws InterruptedException, ExecutionException T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException T getNow(T valueIfAbsent) T join() – Нет checked exceptions (CompletionException) ... stream . map ( x -> C o m p l e t a b l e F u t u r e ...). map ( C o m p l e t a b l e F u t u r e :: join ) ... c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 24/39 Накладные расходы c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 25/39 Бенчмарк: Окружение ∙ ∙ ∙ ∙ Intel Core i5-3320M (1x2x2, 3.3 GHz) Linux x64 (kernel 3.16) JDK 8u40 OpenJDK JMH 1.8 c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 26/39 Бенчмарк: Базовые операции @Param ({ " 1024 " }) public volatile int loada ; @Param ({ " 1024 " }) public volatile int loadb ; Integer a () { Blackhole . consumeCPU ( loada ); return loada ; } Integer b () { Blackhole . consumeCPU ( loadb ); return loadb ; } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 27/39 Бенчмарк: Что сравниваем Простой вариант @Benchmark public Integer ab () { return a () * b (); } @Benchmark public Integer stream () throws InterruptedException , E x e c u t i o n E x c e p t i o n { return IntStream . range (0 , 2) . mapToObj (( i ) -> i == 0 ? a () : b ()) . reduce (1 , (a , b ) -> a * b ); } @Benchmark public Integer parstream () throws InterruptedException , E x e c u t i o n E x c e p t i o n { return IntStream . range (0 , 2). parallel () . mapToObj (( i ) -> i == 0 ? a () : b ()) . reduce (1 , (a , b ) -> a * b ); } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 28/39 Бенчмарк: Что сравниваем Future @Benchmark public Integer future2 () throws InterruptedException , E x e c u t i o n E x c e p t i o n { E xe cu t or S er vi c e fjp = ForkJoinPool . commonPool (); Future < Integer > fa = fjp . submit (() -> a ()); Future < Integer > fb = fjp . submit (() -> b ()); return fa . get () * fb . get (); } @Benchmark public Integer future3 () throws InterruptedException , E x e c u t i o n E x c e p t i o n { E xe cu t or S er vi c e fjp = ForkJoinPool . commonPool (); Future < Integer > fa = fjp . submit (() -> a ()); Future < Integer > fb = fjp . submit (() -> b ()); return fjp . submit (() -> fa . get () * fb . get ()). get (); } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 29/39 Бенчмарк: Что сравниваем CompletableFuture @Benchmark public Integer cf2 () throws InterruptedException , E x e c u t i o n E x c e p t i o n { CompletableFuture < Integer > cfa = C o m p l e t a b l e F u t u r e . supplyAsync (() -> a ()); CompletableFuture < Integer > cfb = C o m p l e t a b l e F u t u r e . supplyAsync (() -> b ()); return cfa . get () * cfb . get (); } @Benchmark public Integer cf3 () throws InterruptedException , E x e c u t i o n E x c e p t i o n { return C o m p l e t a b l e F u t u r e . supplyAsync (() -> a ()) . thenCombine ( C o m p l e t a b l e F u t u r e . supplyAsync (() -> b ()) , (a , b ) -> a * b ). get (); } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 30/39 Бенчмарк: Результаты Последовательная обработка лучше (loada=loadb=1024) Вариант 𝜇c/оп ab 4.7 ± 0.1 cf2 7.9 ± 0.8 cf3 11.4 ± 0.7 future2 12.5 ± 0.4 future3 13.3 ± 0.7 parstream 9.9 ± 0.5 stream 4.9 ± 0.1 c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 31/39 Бенчмарк: Результаты Оценка пустой операции (loada=loadb=0) Вариант ab cf2 cf3 future2 future3 parstream stream нc/оп 5.0 ± 0.7 703.3 ± 285.9 1647.2 ± 523.2 6315.4 ± 632.8 7591.9 ± 1032.3 1234.4 ± 202.8 74.8 ± 5.5 c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 32/39 Бенчмарк: Результаты Параллельная обработка лучше (loada=loadb=131070) Вариант ab cf2 cf3 future2 future3 parstream stream 𝜇c/оп 596.5 ± 2.3 360.0 ± 17.3 342.6 ± 13.5 359.6 ± 7.9 342.5 ± 9.8 334.8 ± 18.4 597.1 ± 2.8 c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 33/39 Пример. Rest-сервис c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 34/39 Сервис: Ингридиенты ∙ ∙ JDK 8u40 JAX-RS 2.0 https://jax-rs-spec.java.net/ ∙ Jersey RI https://jersey.java.net/ ∙ Grizzly NIO framework https://grizzly.java.net/ c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 35/39 Сервис: Ингридиенты ∙ ∙ JDK 8u40 JAX-RS 2.0 https://jax-rs-spec.java.net/ ∙ Jersey RI https://jersey.java.net/ ∙ Grizzly NIO framework https://grizzly.java.net/ ∙ CompletableFuture c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 35/39 Сервис: Запускалка public class Main { public static final String BASE_URI = " http :// localhost :8080/ jpoint / " ; public static void main ( String [] args ) throws IOException { Res ourceC onfig rc = new R esourc eConfi g (). packages ( " com . oracle . demo " ); HttpServer server = G r i z z l y H t t p S e r v e r F a c t o r y . c r e a t e H t t p S e r v e r ( URI . create ( BASE_URI ) , rc ); System . out . println ( String . format ( " Jersey ␣ app ␣ started ␣ " + " with ␣ WADL ␣ available ␣ at ␣ % sapplication . wadl \ n " + " Hit ␣ enter ␣ to ␣ stop ␣ it ... " , BASE_URI )); System . in . read (); server . shutdownNow (); } } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 36/39 Сервис: Endpoint @Path ( " jpoint " ) public class JPoint { @Inject DataService dataService ; @GET @Produces ( MediaType . TEXT_PLAIN ) public void asyncGet ( @Suspended final AsyncResponse asyncResponse ) { dataService . findAudience () . thenCombine ( dataService . fi ndImpr ession () , (a , b ) -> a + b ) . thenApply ( asyncResponse :: resume ) . exceptionally ( asyncResponse :: resume ); // way #1 asyncResponse . setTimeout (1 , SECONDS ); asyncResponse . s e t T i m e o u t H a n d l e r ( ar -> ar . resume ( new T i m e o u t E x c e p t i o n ())); } } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 37/39 Сервис: Provider Часть 1/2 @ManagedBean @Path ( " data " ) public class DataService { // @Inject S c h e d u l e d E x e c u t o r S e r v i c e shedPool = Executors . n e w S c h e d u l e d T h r e a d P o o l (1); public CompletableFuture < String > findAudience () { return find ( " audience " ); } public CompletableFuture < String > findIm pressi on () { return find ( " impression " ); } @PreDestroy public void shutdown () { shedPool . shutdownNow (); } ... c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 38/39 Сервис: Provider Часть 2/2 public CompletableFuture < String > find ( String path ) { CompletableFuture < String > promise = new CompletableFuture < >(); CompletableFuture . runAsync (() -> { try { promise . complete ( new String ( Files . readAllBytes ( Paths . get ( path )))); } catch ( IOException e ) { promise . c o m p l e t e E x c e p t i o n a l l y ( e ); } }); // way #2 shedPool . schedule ( () -> promise . c o m p l e t e E x c e p t i o n a l l y ( new T i m e o u t E x c e p t i o n ()) , 1 , SECONDS ); return promise ; } } c 2015, Oracle and/or its affiliates. All rights reserved. Copyright ○ 39/39
© Copyright 2024