在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、消费前一阶段的功效