mirror of
https://github.com/LingCoder/OnJava8.git
synced 2026-08-24 15:03:29 +08:00
CompletableFuture1
This commit is contained in:
@@ -1272,11 +1272,169 @@ public class QuittingTasks {
|
||||
<!-- CompletableFutures -->
|
||||
## CompletableFuture类
|
||||
|
||||
作为介绍,这里是使用CompletableFutures在QuittingTasks.java中:
|
||||
|
||||
```java
|
||||
// concurrent/QuittingCompletable.java
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
import java.util.concurrent.*;
|
||||
import onjava.Nap;
|
||||
public class QuittingCompletable {
|
||||
public static void main(String[] args) {
|
||||
List<QuittableTask> tasks =
|
||||
IntStream.range(1, QuittingTasks.COUNT)
|
||||
.mapToObj(QuittableTask::new)
|
||||
.collect(Collectors.toList());
|
||||
List<CompletableFuture<Void>> cfutures =
|
||||
tasks.stream()
|
||||
.map(CompletableFuture::runAsync)
|
||||
.collect(Collectors.toList());
|
||||
new Nap(1);
|
||||
tasks.forEach(QuittableTask::quit);
|
||||
cfutures.forEach(CompletableFuture::join);
|
||||
}
|
||||
}
|
||||
/* Output:7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 2526 27 28 29 30 31 32 33 34 6 35 4 38 39 40 41 42 43 4445 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 6263 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 8081 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 9899 100 101 102 103 104 105 106 107 108 109 110 111 1121 113 114 116 117 118 119 120 121 122 123 124 125 126127 128 129 130 131 132 133 134 135 136 137 138 139 140141 142 143 144 145 146 147 148 149 5 115 37 36 2 3*/
|
||||
```
|
||||
|
||||
任务是一个**List <QuittableTask>**,就像在**QuittingTasks.java**中一样,但是在这个例子中,没有**peek()**将每个**QuittableTask**提交给**ExecutorService**。相反,在创建cfutures期间,每个任务都交给**CompletableFuture::runAsync**。这执行**VerifyTask.run(**)并返回**CompletableFuture <Void>**。因为**run()**不返回任何内容,所以在这种情况下我只使用**CompletableFuture**调用**join()**来等待它完成。
|
||||
|
||||
在此示例中需要注意的重要事项是,运行任务不需要**ExecutorService**。这由**CompletableFuture**管理(尽管有提供自己的**ExecutorService**的选项)。你也不需要调用**shutdown()**;事实上,除非你像我这样明确地调用**join()**,程序将尽快退出,而不必等待任务完成。
|
||||
|
||||
这个例子只是一个起点。你很快就会看到ComplempleFutures能够做得更多。
|
||||
|
||||
### 基本用法
|
||||
|
||||
这是一个带有静态方法**work()**的类,它对该类的对象执行某些工作:
|
||||
|
||||
```java
|
||||
// concurrent/Machina.java
|
||||
import onjava.Nap;
|
||||
public class Machina {
|
||||
public enum State {
|
||||
START, ONE, TWO, THREE, END;
|
||||
State step() {
|
||||
if(equals(END))
|
||||
return END;
|
||||
return values()[ordinal() + 1];
|
||||
}
|
||||
}
|
||||
private State state = State.START;
|
||||
private final int id;
|
||||
public Machina(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
public static Machina work(Machina m) {
|
||||
if(!m.state.equals(State.END)){
|
||||
new Nap(0.1);
|
||||
m.state = m.state.step();
|
||||
}
|
||||
System.out.println(m);return m;
|
||||
}
|
||||
@Override
|
||||
public StringtoString() {
|
||||
return"Machina" + id + ": " + (state.equals(State.END)? "complete" : state);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
这是一个有限状态机,一个微不足道的机器,因为它没有分支......它只是从头到尾遍历一条路径。**work()**方法将机器从一个状态移动到下一个状态,并且需要100毫秒才能完成“工作”。
|
||||
|
||||
我们可以用**CompletableFuture**做的一件事是使用**completedFuture()**将它包装在感兴趣的对象中
|
||||
|
||||
```java
|
||||
// concurrent/CompletedMachina.java
|
||||
import java.util.concurrent.*;
|
||||
public class CompletedMachina {
|
||||
public static void main(String[] args) {
|
||||
CompletableFuture<Machina> cf =
|
||||
CompletableFuture.completedFuture(
|
||||
new Machina(0));
|
||||
try {
|
||||
Machina m = cf.get(); // Doesn't block
|
||||
} catch(InterruptedException |
|
||||
ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**completedFuture()**创建一个“已经完成”的**CompletableFuture**。对这样一个未来做的唯一有用的事情是**get()**里面的对象,所以这看起来似乎没有用。注意**CompletableFuture**被输入到它包含的对象。这个很重要。
|
||||
|
||||
通常,**get()**在等待结果时阻塞调用线程。此块可以通过**InterruptedException**或**ExecutionException**中断。在这种情况下,阻止永远不会发生,因为CompletableFutureis已经完成,所以答案立即可用。
|
||||
|
||||
当我们将Machina包装在CompletableFuture中时,我们发现我们可以在CompletableFuture上添加操作来处理所包含的对象,事情变得更加有趣:
|
||||
|
||||
```java
|
||||
// concurrent/CompletableApply.java
|
||||
import java.util.concurrent.*;
|
||||
public class CompletableApply {
|
||||
public static void main(String[] args) {
|
||||
CompletableFuture<Machina> cf =
|
||||
CompletableFuture.completedFuture(
|
||||
new Machina(0));
|
||||
CompletableFuture<Machina> cf2 =
|
||||
cf.thenApply(Machina::work);
|
||||
CompletableFuture<Machina> cf3 =
|
||||
cf2.thenApply(Machina::work);
|
||||
CompletableFuture<Machina> cf4 =
|
||||
cf3.thenApply(Machina::work);
|
||||
CompletableFuture<Machina> cf5 =
|
||||
cf4.thenApply(Machina::work);
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
Machina0: ONE
|
||||
Machina0: TWO
|
||||
Machina0: THREE
|
||||
Machina0: complete
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
**thenApply()**应用一个接受输入并产生输出的函数。在这种情况下,**work()**函数产生与它相同的类型,因此每个得到的**CompletableFuture**仍然被输入为**Machina**,但是(类似于**Streams**中的**map()**)**Function**也可以返回不同的类型,这将反映在返回类型
|
||||
|
||||
您可以在此处看到有关CompletableFutures的重要信息:它们会在您执行操作时自动解包并重新包装它们所携带的对象。这样你就不会陷入麻烦的细节,这使得编写和理解代码变得更加简单。
|
||||
|
||||
我们可以消除中间变量并将操作链接在一起,就像我们使用Streams一样:
|
||||
|
||||
```java
|
||||
// concurrent/CompletableApplyChained.javaimport java.util.concurrent.*;
|
||||
import onjava.Timer;
|
||||
public class CompletableApplyChained {
|
||||
public static void main(String[] args) {
|
||||
Timer timer = new Timer();
|
||||
CompletableFuture<Machina> cf =
|
||||
CompletableFuture.completedFuture(
|
||||
new Machina(0))
|
||||
.thenApply(Machina::work)
|
||||
.thenApply(Machina::work)
|
||||
.thenApply(Machina::work)
|
||||
.thenApply(Machina::work);
|
||||
System.out.println(timer.duration());
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
Machina0: ONE
|
||||
Machina0: TWO
|
||||
Machina0: THREE
|
||||
Machina0: complete
|
||||
514
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
在这里,我们还添加了一个**Timer**,它向我们展示每一步增加100毫秒,还有一些额外的开销。
|
||||
**CompletableFutures**的一个重要好处是它们鼓励使用私有子类原则(不分享任何东西)。默认情况下,使用**thenApply()**来应用一个不与任何人通信的函数 - 它只需要一个参数并返回一个结果。这是函数式编程的基础,并且它在并发性方面非常有效。并行流和ComplempleFutures旨在支持这些原则。只要您不决定共享数据(共享非常容易,甚至意外)您可以编写相对安全的并发程序。
|
||||
|
||||
<!-- Deadlock -->
|
||||
## 死锁
|
||||
|
||||
|
||||
|
||||
<!-- Constructors are not Thread-Safe -->
|
||||
## 构造函数非线程安全
|
||||
|
||||
|
||||
Reference in New Issue
Block a user