CompletableFuture уже здесь

49
CompletableFuture уже здесь Дмитрий Чуйко [email protected] Copyright c 2015, Oracle and/or its affiliates. All rights reserved.

Transcript of CompletableFuture уже здесь

Page 1: CompletableFuture уже здесь

CompletableFutureуже здесь

Дмитрий Чуйко[email protected]

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved.

Page 2: CompletableFuture уже здесь

Содержание

Введение

API

Накладные расходы

Пример. Rest-сервис

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 2/45

Page 3: CompletableFuture уже здесь

Safe Harbor Statement

The following is intended to outline our general product direction. Itis intended for information purposes only, and may not beincorporated into any contract. It is not a commitment to deliver anymaterial, code, or functionality, and should not be relied upon inmaking purchasing decisions. The development, release, and timingof any features or functionality described for Oracle’s productsremains at the sole discretion of Oracle.

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 3/45

Page 4: CompletableFuture уже здесь

Введение

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 4/45

Page 5: CompletableFuture уже здесь

Параллелизм в Java: *Отступление

∙ JDK 7 EOL∙ JDK 8u∙ JDK 9 EA

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 5/45

Page 6: CompletableFuture уже здесь

Параллелизм в Java: История

∙ Threads– Monitors– Locks and other primitives

∙ Executors– Runnable<T>, Callable<T> → lambdas

∙ Future<T>∙ ForkJoinPool∙ stream.parallel()∙ Explicit → implicit

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 6/45

Page 7: CompletableFuture уже здесь

Параллелизм в Java: Future<T>

∙ Обёртка для результата, доступного в будущем∙ Получение значения требует проверки исключений

– ExecutionException содержит исходное исключение∙ Исполняется в каком-то потоке и блокирует какой-то

(другой) поток∙ Можно проверить, доступно ли уже значение∙ Можно отменить вычисление

Future f = executor.submit (() -> ...);result = f.get(); // love to be BLOCKED here

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 7/45

Page 8: CompletableFuture уже здесь

Сложности: Обработка ошибок

try {try {

return parse(fileObject , content.get ());} catch (ExecutionException e) {

unfold(e);}

} catch (IOException e) {log.error(e, fileObject );

} catch (InterruptedException e) {throw new RuntimeException(e);

}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 8/45

Page 9: CompletableFuture уже здесь

Сложности: Обработка ошибок

private static void unfold(ExecutionException e) throws IOException ,InterruptedException {

Throwable cause = e.getCause ();if (cause instanceof ExecutionException)

unfold (( ExecutionException) cause);if (cause instanceof IOException)

throw (IOException) cause;if (cause instanceof InterruptedException)

throw (InterruptedException) cause;if (cause instanceof Error)

throw (Error) cause;if (cause instanceof RuntimeException)

throw (RuntimeException) cause;throw new RuntimeException(e);

}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 9/45

Page 10: CompletableFuture уже здесь

Сложности: Давайте добавим обработчики!

readFileAsync(file ,content -> System.out.println(content),ex -> ex.printStackTrace ();

);

∙ ↓Добро пожаловать сюда↓http://callbackhell.com/

readFileAsync(file ,content -> processContentAsync(content ,

c -> System.out.println(c),e -> e.printStackTrace ()

);ex -> ex.printStackTrace ();

);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 10/45

Page 11: CompletableFuture уже здесь

Сложности: Давайте добавим обработчики!

readFileAsync(file ,content -> System.out.println(content),ex -> ex.printStackTrace ();

);

∙ ↓Добро пожаловать сюда↓http://callbackhell.com/

readFileAsync(file ,content -> processContentAsync(content ,

c -> System.out.println(c),e -> e.printStackTrace ()

);ex -> ex.printStackTrace ();

);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 10/45

Page 12: CompletableFuture уже здесь

Сложности: Результат

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 11/45

Page 13: CompletableFuture уже здесь

CompletableFuture: Боремся с вложенностью

CompletableFuture.supplyAsync (() -> readFile(file)).thenComposeAsync(content -> processContent(content )).whenComplete ((result , ex) -> {

if (ex == null) {System.out.println(result );

} else {ex.printStackTrace ();

}});

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 12/45

Page 14: CompletableFuture уже здесь

CompletableFuture: Композиция

∙ Method chaining– Нет блокирующих вызовов– Знакомо и удобно (builders, mocks, streams)

∙ Работаем с несколькими CF

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 13/45

Page 15: CompletableFuture уже здесь

API

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 14/45

Page 16: CompletableFuture уже здесь

Что за класс: CompletableFuture<T>

∙ Core library class since Java SE 8∙ implements Future<T>∙ implements CompletionStage<T>

– Элемент композиции– Вычисление функции– Связь через результаты– Методы преобразований– toCompletableFuture()

∙ Асинхронные операции

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 15/45

Page 17: CompletableFuture уже здесь

Методы: Создание

∙ CompletableFuture()– boolean complete(T value), успешно только для одного потока– boolean completeExceptionally(Throwable ex)

∙ CompletableFuture<U> completedFuture(U value)∙ CompletableFuture<U>

supplyAsync(Supplier<U> supplier [, Executor executor])∙ CompletableFuture<Void>

runAsync(Runnable runnable [, Executor executor])∙ ForkJoinPool.commonPool() по умолчанию

– если выключен, new Thread()

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 16/45

Page 18: CompletableFuture уже здесь

Методы: Создание

CompletableFuture <Long > cf1 = CompletableFuture.supplyAsync (() -> 42L);CompletableFuture <Long > start = CompletableFuture.completedFuture (42L);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 17/45

Page 19: CompletableFuture уже здесь

Методы: *ОтступлениеУпрощённая запись generics

∙ Function<? super T,? extends U>→ Function<T,U>

∙ Consumer<? super T> → Consumer<T>∙ . . .

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 18/45

Page 20: CompletableFuture уже здесь

Методы: Трансформации

∙ CompletableFuture<U> thenApply(Function<T,U> fn)– Нет "Async"→ продолжаем в том же потоке

∙ CompletableFuture<U>thenApplyAsync(Function<T,U> fn [, Executor executor])

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 19/45

Page 21: CompletableFuture уже здесь

Методы: Трансформации (map)

CompletableFuture <Long > cf2 = CompletableFuture.supplyAsync (() -> 42L).thenApply(r1 -> r1 + 2015);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 20/45

Page 22: CompletableFuture уже здесь

Методы: Подписка

∙ CompletableFuture<Void> thenAccept(Consumer<T> block);∙ CompletableFuture<Void> thenRun(Runnable action);∙ Async versions

CompletableFuture <Void > cf3 = CompletableFuture.supplyAsync (() -> 42L).thenApply(r1 -> r1 + 2015).thenAccept(System.out:: println );

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 21/45

Page 23: CompletableFuture уже здесь

Методы: Обработка ошибок

∙ CompletableFuture<T>exceptionally(Function<Throwable, T> fn)

∙ CompletableFuture<U>handle(BiFunction<T, Throwable, U> fn)

∙ Ошибка пробрасывается по цепочкам

CompletableFuture.supplyAsync (() -> readFile(file)).thenComposeAsync(content -> processContent(content )).thenAccept(System.out:: println).exceptionally(Throwable :: printStackTrace );

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 22/45

Page 24: CompletableFuture уже здесь

Методы: Обработка ошибок

CompletableFuture <Void > cf = new CompletableFuture <>();

cf.completeExceptionally(new RuntimeException ());//cf.completeExceptionally(new CompletionException(new RuntimeException ()));

cf.exceptionally(e -> {System.out.println(e);return null;

});

cf.thenApply(Function.identity ()). exceptionally(e -> {System.out.println(e); // CompletionException:RuntimeException - not this stagereturn null;

});

cf.get(); // ExecutionException:RuntimeException

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 23/45

Page 25: CompletableFuture уже здесь

Методы: Комбинация (reduce)

∙ CompletableFuture<V>thenCombine (CompletionStage<U> other,BiFunction<T,U,V> fn)

CompletableFuture <Long > cf2 = CompletableFuture.supplyAsync (() -> 42L).thenCombine(CompletableFuture.supplyAsync (() -> 2015), Math::min);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 24/45

Page 26: CompletableFuture уже здесь

Методы: Для набора

∙ CompletableFuture<Object>anyOf(CompletableFuture<?>... cfs)

∙ CompletableFuture<Void>allOf(CompletableFuture<?>... cfs)

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 25/45

Page 27: CompletableFuture уже здесь

Методы: Композиция (flatMap)

∙ CompletableFuture<U>thenCompose(Function<T,CompletableFuture<U>> fn)

CompletableFuture <Long > cff = CompletableFuture.supplyAsync (() -> 42L).thenCompose(x -> CompletableFuture.supplyAsync (() -> x + 2015));

CompletableFuture <CompletableFuture <Long >> cff = CompletableFuture.supplyAsync (() -> 42L).thenApply(x -> CompletableFuture.supplyAsync (() -> x + 2015));

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 26/45

Page 28: CompletableFuture уже здесь

Методы: 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 -> CompletableFuture ...). map(CompletableFuture ::join)...

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 27/45

Page 29: CompletableFuture уже здесь

Методы: Get

// parallel where?stream.parallel ()

.map(x -> CompletableFuture.supplyAsync ...)

.map(CompletableFuture ::join);

// NOT Executors.newSingleThreadExecutor ();ExecutorService es1 = new ForkJoinPool (1);Future <?> task1 = es1.submit (() -> {

try {es1.submit(()->System.out.println("1")).get ();

} catch (Exception e) {}

});task1.get();

// parallel where?CompletableFuture.supplyAsync (() -> stream (). parallel ()..., fjpN);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 28/45

Page 30: CompletableFuture уже здесь

Методы: Get

// parallel where?stream.parallel ()

.map(x -> CompletableFuture.supplyAsync ...)

.map(CompletableFuture ::join);

// NOT Executors.newSingleThreadExecutor ();ExecutorService es1 = new ForkJoinPool (1);Future <?> task1 = es1.submit (() -> {

try {es1.submit(()->System.out.println("1")).get ();

} catch (Exception e) {}

});task1.get();

// parallel where?CompletableFuture.supplyAsync (() -> stream (). parallel ()..., fjpN);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 28/45

Page 31: CompletableFuture уже здесь

Методы: Get

// parallel where?stream.parallel ()

.map(x -> CompletableFuture.supplyAsync ...)

.map(CompletableFuture ::join);

// NOT Executors.newSingleThreadExecutor ();ExecutorService es1 = new ForkJoinPool (1);Future <?> task1 = es1.submit (() -> {

try {es1.submit(()->System.out.println("1")).get ();

} catch (Exception e) {}

});task1.get();

// parallel where?CompletableFuture.supplyAsync (() -> stream (). parallel ()..., fjpN);

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 28/45

Page 32: CompletableFuture уже здесь

Методы: Исполнение в потоках

∙ isDone() → исполнение метода в текущем потоке– Если не ...Async()– И для exceptionally()

∙ helpPostComplete() на любой чих помогаем будить ждущих– И для exceptionally()– И для повторных вызовов complete()

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 29/45

Page 33: CompletableFuture уже здесь

Накладные расходы

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 30/45

Page 34: CompletableFuture уже здесь

Бенчмарк: Окружение

∙ Intel Core i5-3320M (1x2x2, 3.3 GHz)∙ Linux x64 (kernel 3.19)∙ JDK 9 EA (b64)∙ OpenJDK JMH 1.10-SNAPSHOT

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 31/45

Page 35: CompletableFuture уже здесь

Бенчмарк: Базовые операции

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

}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 32/45

Page 36: CompletableFuture уже здесь

Бенчмарк: Что сравниваемПростой вариант

@Benchmarkpublic Integer ab() {

return a() * b();}

@Benchmarkpublic Integer stream () throws InterruptedException , ExecutionException {

return IntStream.range(0, 2).mapToObj ((i) -> i == 0 ? a() : b()).reduce(1, (a, b) -> a * b);

}

@Benchmarkpublic Integer parstream () throws InterruptedException , ExecutionException {

return IntStream.range(0, 2). parallel ().mapToObj ((i) -> i == 0 ? a() : b()).reduce(1, (a, b) -> a * b);

}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 33/45

Page 37: CompletableFuture уже здесь

Бенчмарк: Что сравниваемFuture

@Benchmarkpublic Integer future2 () throws InterruptedException , ExecutionException {

ExecutorService fjp = ForkJoinPool.commonPool ();Future <Integer > fa = fjp.submit (() -> a());Future <Integer > fb = fjp.submit (() -> b());return fa.get() * fb.get ();

}

@Benchmarkpublic Integer future3 () throws InterruptedException , ExecutionException {

ExecutorService fjp = ForkJoinPool.commonPool ();Future <Integer > fa = fjp.submit (() -> a());Future <Integer > fb = fjp.submit (() -> b());return fjp.submit (() -> fa.get() * fb.get ()). get();

}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 34/45

Page 38: CompletableFuture уже здесь

Бенчмарк: Что сравниваемCompletableFuture

@Benchmarkpublic Integer cf2() throws InterruptedException , ExecutionException {

return CompletableFuture.supplyAsync (() -> a()).thenCombine(CompletableFuture.supplyAsync (() -> b()), (a, b) -> a * b).get ();

}

@Benchmarkpublic Integer cf3() throws InterruptedException , ExecutionException {

return CompletableFuture.supplyAsync (() -> a()).thenCombineAsync(CompletableFuture.supplyAsync (() -> b()), (a, b) -> a * b).get ();

}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 35/45

Page 39: CompletableFuture уже здесь

Бенчмарк: РезультатыПараметры по умолчанию (loada=loadb=1K)

Вариант 𝜇c/опab 6 ± 1

cf2 4 ± 1

cf3 4 ± 1

future2 8 ± 1

future3 8 ± 1

parstream 7 ± 1

stream 6 ± 1

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 36/45

Page 40: CompletableFuture уже здесь

Бенчмарк: РезультатыОценка пустой операции (loada=loadb=0)

Вариант Время, нc/оп Аллокации, B/опab 11 ± 1 0 ± 0

cf2 715 ± 11 200 ± 1

cf3 1060 ± 17 204 ± 2

future2 4733 ± 135 80 ± 1

future3 4657 ± 213 128 ± 1

parstream 421 ± 24 496 ± 1

stream 131 ± 1 248 ± 1

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 37/45

Page 41: CompletableFuture уже здесь

Бенчмарк: РезультатыДолгая операция (loada=loadb=128K)

Вариант 𝜇c/опab 713 ± 1

cf2 383 ± 8

cf3 393 ± 10

future2 386 ± 8

future3 387 ± 9

parstream 378 ± 10

stream 713 ± 1

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 38/45

Page 42: CompletableFuture уже здесь

Пример. Rest-сервис

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 39/45

Page 43: CompletableFuture уже здесь

Сервис: Ингридиенты

∙ JDK 8u25∙ JAX-RS 2.0

https://jax-rs-spec.java.net/∙ Jersey RI

https://jersey.java.net/∙ Grizzly NIO framework

https://grizzly.java.net/

∙ CompletableFuture

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 40/45

Page 44: CompletableFuture уже здесь

Сервис: Ингридиенты

∙ JDK 8u25∙ JAX-RS 2.0

https://jax-rs-spec.java.net/∙ Jersey RI

https://jersey.java.net/∙ Grizzly NIO framework

https://grizzly.java.net/∙ CompletableFuture

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 40/45

Page 45: CompletableFuture уже здесь

Сервис: Запускалка

public class Main {public static final String BASE_URI = "http :// localhost :8080/ jee/";

public static void main(String [] args) throws IOException {ResourceConfig rc = new ResourceConfig (). packages("com.oracle.demo");HttpServer server = GrizzlyHttpServerFactory

.createHttpServer(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 ();

}}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 41/45

Page 46: CompletableFuture уже здесь

Сервис: Endpoint

@Path("jeeconf")public class JEEConf {

@InjectDataService dataService;// @ManagedAsync -- NOT NEEDED@GET@Produces(MediaType.TEXT_PLAIN)public void asyncGet(@Suspended final AsyncResponse asyncResponse) {

dataService.findAudience ().thenCombine(dataService.findImpression (), (a, b) -> a + b).thenApply(asyncResponse :: resume).exceptionally(asyncResponse :: resume );

// way #1asyncResponse.setTimeout (1, SECONDS );asyncResponse.setTimeoutHandler(ar -> ar.resume(new TimeoutException ()));

}}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 42/45

Page 47: CompletableFuture уже здесь

Сервис: ProviderЧасть 1/2

@ManagedBean@Path("data")public class DataService {

// @InjectScheduledExecutorService shedPool = Executors.newScheduledThreadPool (1);

public CompletableFuture <String > findAudience () {return find("audience");

}public CompletableFuture <String > findImpression () {

return find("impression");}@PreDestroypublic void shutdown () {

shedPool.shutdownNow ();}...

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 43/45

Page 48: CompletableFuture уже здесь

Сервис: 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.completeExceptionally(e);}

});// way #2. and impact on shedPool.shedPool.schedule(

() -> promise.completeExceptionally(new TimeoutException ()), 1, SECONDS );return promise;

}}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 44/45

Page 49: CompletableFuture уже здесь

Сервис: ExceptionMapper

@Providerpublic class CompletionExceptionMapper

implements ExceptionMapper <CompletionException > {

public Response toResponse(CompletionException bex) {return Response.status(Status.BAD_REQUEST)

.entity(new File("error.png")). type("image/png"). build ();}

}

Copyright c○ 2015, Oracle and/or its affiliates. All rights reserved. 45/45