在Java中异步编程,不必然非要利用rxJava, Java自己的库中的CompletableFuture可以很好的应对大部门的场景。
原文: 20 Examples of Using Java’s CompletableFuture, 作者 Mahmoud Anouti。
这篇文章先容 Java 8 的 CompletionStage API和它的尺度库的实现 CompletableFuture。API通过例子的方法演示了它的行为,每个例子演示一到两个行为。
既然CompletableFuture类实现了CompletionStage接口,首先我们需要领略这个接口的契约。它代表了一个特定的计较的阶段,可以同步可能异步的被完成。你可以把它当作一个计较流水线上的一个单位,最终会发生一个最终功效,这意味着几个CompletionStage可以串联起来,昆山软件开发,一个完成的阶段可以触发下一阶段的执行,接着触发下一次,接着……
除了实现CompletionStage接口, CompletableFuture也实现了future接口, 代表一个未完成的异步事件。CompletableFuture提供了要领,可以或许显式地完成这个future,所以它叫CompletableFuture。
1、 建设一个完成的CompletableFuture
最简朴的例子就是利用一个预界说的功效建设一个完成的CompletableFuture,凡是我们会在计较的开始阶段利用它。
static void completedFutureExample() {
CompletableFuture cf = CompletableFuture.completedFuture("message");
assertTrue(cf.isDone());
assertEquals("message", cf.getNow(null));
}
getNow(null)要领在future完成的环境下会返回功效,就好比上面这个例子,不然返回null (传入的参数)。
2、运行一个简朴的异步阶段
这个例子建设一个一个异步执行的阶段:
static void runAsyncExample() {
CompletableFuture cf = CompletableFuture.runAsync(() -> {
assertTrue(Thread.currentThread().isDaemon());
randomSleep();
});
assertFalse(cf.isDone());
sleepEnough();
assertTrue(cf.isDone());
}
通过这个例子可以学到两件工作:
CompletableFuture的要领假如以Async末了,它会异步的执行(没有指定executor的环境下), 异步执行通过ForkJoinPool实现, 它利用守护线程去执行任务。留意这是CompletableFuture的特性, 其它CompletionStage可以override这个默认的行为。
3、在前一个阶段上应用函数
下面这个例子利用前面 #1 的完成的CompletableFuture, #1返回功效为字符串message,然后应用一个函数把它酿成大写字母。
static void thenApplyExample() {
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApply(s -> {
assertFalse(Thread.currentThread().isDaemon());
return s.toUpperCase();
});
assertEquals("MESSAGE", cf.getNow(null));
}
留意thenApply要领名称代表的行为。
then意味着这个阶段的行动产生当前的阶段正常完成之后。本例中,当前节点完成,返回字符串message。
Apply意味着返回的阶段将会对功效前一阶段的功效应用一个函数。
函数的执行会被阻塞,这意味着getNow()只有打斜操纵被完成后才返回。
4、在前一个阶段上异步应用函数
通过挪用异步要领(要领后边加Async后缀),串联起来的CompletableFuture可以异步地执行(利用ForkJoinPool.commonPool())。
static void thenApplyAsyncExample() {
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
assertTrue(Thread.currentThread().isDaemon());
randomSleep();
return s.toUpperCase();
});
assertNull(cf.getNow(null));
assertEquals("MESSAGE", cf.join());
}
5、利用定制的Executor在前一个阶段上异步应用函数
异步要领一个很是有用的特性就是可以或许提供一个Executor来异步地执行CompletableFuture。这个例子演示了如何利用一个牢靠巨细的线程池来应用大写函数。
static ExecutorService executor = Executors.newFixedThreadPool(3, new ThreadFactory() {
int count = 1;
@Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "custom-executor-" + count++);
}
});
static void thenApplyAsyncWithExecutorExample() {
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
assertTrue(Thread.currentThread().getName().startsWith("custom-executor-"));
assertFalse(Thread.currentThread().isDaemon());
randomSleep();
return s.toUpperCase();
}, executor);
assertNull(cf.getNow(null));
assertEquals("MESSAGE", cf.join());
}
6、消费前一阶段的功效