初探
CompletableFuture
@kojilin
twjug 2013/9/7
Long running task
● Dependent Tasks
Retrieving data from server
Processing data
Writing to storage
Showing result to user
Blocking API
executor.execute(() -> {
UserDto dto = service.retrieveUser();
User user = accounts.processUser(dto);
Storage.writeUser(user);
});
● Coarse-grained
– Web service, DB, Process Data
● Control flow is verbose
– if-else, try-catch-finally
executor.execute(() -> {
try {
UserDto dto = service.retrieveUser();
if(dto == null)
return;
User user = accounts.processDto(dto);
Storage.writeUser(user);
}
catch(RemoteException e) {
// alert user
}
finally {
// ...
}
Non-blocking API
void Service#retrieveUser(callback);
void Accounts#processUser(dto, callback);
void Storage#writeUser(user, callback);
● When Task B depends on Task A
● A → B → C → D → E → …
Chaining async call
step1(function (value1){
step2(value1, function(value2){
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
Non-blocking API
Future<UserDto> Service#retrieveUser();
Future<User> Accounts#processUser(dto);
Future<User> Storage#writeUser(user);
● No more callback hell
Chaining async call
future = step1();
future.then(value1 -> {step2(value1)})
.then(value2 -> {step3(value2)})
.then(value3 -> {step4(value3)})
.onComplete(value4 -> {
// Do something with value 4
});
jQuery
// $.get returns a jqXHR(derived from a
// Deferred object)
var request = $.get(url);
var chained = request.then(
function(data) {
return $.get(url2, {user:data.userId});
});
chained.done(function(data) {
// ...
});
Guava
ListenableFuture<User> f1 =
service.retrieveUserInfo();
ListenableFuture<User> f2 =
Futures.transform(future1,
(AsyncFunction<UserDto, User>) dto -> {
return accounts.processDto(dto);
});
ListenableFuture<User> f3 =
Futures.transform(future2,
(AsyncFunction<User, User>) user ->{
return storage.writeUser(user);
});
Scala
val f1 = future{ service.retrieveUserInfo() }
val f2 = f1.map{ dto =>
accounts.processDto(dto)
}
val f3 = f2.map{ user=>
storage.writeUser(user)
}
f3 onComplete{
case Success(_) => …
case Failure(t) => println()
}
What is Future?
● Future, promise, and delay
– They describe an acts as a proxy for a result that is
initially unknown, usually because the computation
of its value is yet incomplete
– They are often used Interchangeably
● Some differences in usage
between future and promise
– Future read
– Promise write
Future API
● jQuery
– Deferred Object
– deferred.promise()
● Java
– Future
● .Net Framework
– Task
– Async & Await keyword
● Scala
– Future & Promise
Future
● java.util.concurrent.Future
future = downloadSite();
// do something
future.get();
future.get(3, TimeUnit.SECONDS);
future.getNow();
Java SE 8
CompletableFuture
CompletableFuture
● Functional
● Monadic
● Asynchronous
● Event-driven
下載和安裝
● Downlaod from
http://jdk8.java.net/lambda/
● Unzip it !!
● 本投影片是基於b105
JavaDoc
@FunctionalInterface
● Supplier<T>
– T get()
● Runnable
– void run()
● Function<T, R>
– R apply(T t)
● Consumer
– void accept(T t)
@FunctionalInterface
● BiFunction<T, U, R>
– R apply(T t, U u)
● BiConsumer<T, U>
– void accept(T t, U u)
類別宣告
public class CompletableFuture<T>
implements Future<T>, CompletionStage<T>
{
// ...
}
使用方式
CompletableFuture<String> doSomeThing()
{
final CompletableFuture<String> future = new
CompletableFuture<>();
// async call complete,
// completeExceptionally, cancel
return future;
}
Write methods
● When two or more threads attempt to
complete, completeExceptionally, or
cancel a CompletableFuture, only one
of them succeeds
/*
* @param mayInterruptIfRunning this value has no effect in
* this implementation because interrupts are not used to
* control processing.
**/
public boolean cancel(boolean
mayInterruptIfRunning)
使用方式
CompletableFuture.supplyAsync(() -> {
// long running job...
return result;
});
CompletableFuture.runAsync(() -> {
// long running job
});
使用端等待結果
future = doSomeThing();
future.get();
future.get(3, TimeUnit.SECONDS);
future.getNow();
使用端使用 Callback
future = doSomeThing();
future.whenComplete((result, throwable -> {
if(throwable != null){
return;
}
//... do something with result
});
Error handling
future = downloadPage();
future.exceptionally(ex -> {
return defaultContent;
});
CompletableFuture<T> exceptionally(
Function<Throwable,? extends T> fn)
whenComplete
CompletableFuture<T> whenComplete(
BiConsumer<? super T,? super Throwable>
action)
future = doSomeThing();
/** returns a new CompletionStage with
* the same result or exception as this stage
*/
future2 =
future.whenComplete((result, throwable -> {
//... do something with result
});
handle
future = doSomeThing();
future.handle((result, throwable -> {
//... do something with result
return 12;
});
CompletableFuture<U> handle(
BiFunction<? Super T, Throwable , ? extends
U> fn)
Transforming
future = downloadPage();
future.thenApply(s -> {
return s.size();
});
<U> CompletableFuture<U> thenApply(
Function<? super T,? extends U> fn)
Chaining
future = downloadPage();
future.thenCompose(s -> {
return parsePage(s);
});
<U> CompletableFuture<U> thenCompose(
Function<? super T, CompletableFuture<U>> fn)
After complete
future = downloadPage();
future.thenRun(() -> {
// ...
});
CompletableFuture<Void> thenAccept(
Consumer<? super T> block)
CompletableFuture<Void> thenRun(
Runnable action)
After Both
CompletableFuture<Void> thenAcceptBoth(
CompletableFuture<? extends U> other,
BiConsumer<? super T, ? super U> action)
CompletableFuture<Void> runAfterBoth(
CompletableFuture<?> other,
Runnable action)
Transform After Either
future = downloadPage(site1);
future.applyToEither(downloadPage(site2),
S -> {
// ...
return result;
});
CompletableFuture<Void> applyToEither(
CompletableFuture<? extends T> other,
Function<? super T, U> fn)
After Either
CompletableFuture<Void> acceptEither(
CompletableFuture<? extends T> other,
Consumer<? super T> action)
CompletableFuture<Void> runAfterEither(
CompletableFuture<?> other,
Runnable action)
Any 和 All
static CompletableFuture<Void> all(
CompletableFuture<?>... cfs)
static CompletableFuture<Object> anyOf(
CompletableFuture<?>... cfs)
API variation
xXXX(XXX xxx)
xXXXAsync(XXX xxx)
xXXXAsync(XXX xxx, Executor executor)
API variation
● Without Async postfix
– By the thread complete current future or any
other caller of a completion method
● With Async postfix
– Using ForkJoinPool.commonPool()
● With Async postfix and Executor
param
– Using Executor
注意
● 自己控制complete方法
future.thenAccept(r -> {
// ...
});
executor.execute(() -> {
future.complete(result);
// ...
accounts.create(result.icon);
});
注意
● 自己控制complete方法
future.thenAccept(r -> {
// ...
});
executor.execute(() -> {
future.complete(result);
// ...
accounts.create(result.icon);
});
1 2
注意
● 自己控制complete方法
future.thenAcceptAsync(r -> {
// ...
});
executor.execute(() -> {
future.complete(result);
// ...
accounts.create(result.icon);
});
注意
● 自己控制complete方法
future.thenAcceptAsync(r -> {
// ...
}, executor);
executor.execute(() -> {
future.complete(result);
// ...
accounts.create(result.icon);
});
注意
● 自己控制complete方法
future.thenAcceptAsync(r -> {
// ...
}, executor);
executor.execute(() -> {
future.complete(result);
// ...
accounts.create(result.icon);
});
newSingleThreadExecutor
newCachedThreadPool
參考資料
● Java Concurrency in Practice
● The way of the Future, Futures in .NET, Java
and JavaScript
– http://blog.softmemes.com/2012/06/18/the-way-of-the-fu
● [concurrency-interest] Interface
CompletionStage
– http://cs.oswego.edu/pipermail/concurrency-interest/201
參考資料
● SIP-14 - Futures and Promises
– http://docs.scala-lang.org/sips/pending/futures-promises
● Java 8: Definitive guide to CompletableFuture
– http://nurkiewicz.blogspot.no/2013/05/java-8-definitive-g
● Java 8: CompletableFuture in action
– http://nurkiewicz.blogspot.no/2013/05/java-8-completabl
● Futures and Promises in Scala 2.10
– https://speakerdeck.com/heathermiller/futures-and-prom

CompletableFuture