CompletableFuture: 組合式異步編程
1.先了解下什麼是吞吐量:
吞吐量是指對網絡、設備、端口、虛電路或其他設施,單位時間內成功地傳送數據的數量(以比特、字節、分組等測量)。(百科)
2.併發,並行:
併發:單個處理器核在多個任務之間切換處理
並行:多個處理器核同時處理多個任務
Future 接口
Future接口建模了一種異步計算,返回一個執行運算結果的引用,當運算結束後,這個運用hui被返回調用方。
(簡單說就是你去奶茶店排隊買奶茶,店員給你一個序號,你就不用在那裏等待,可以去做其他事,等好了再去拿,這就是異步)
例子:
ExecutorService executor = Executors.newCachedThreadPool();
Future<Double> future = executor.submit(new Callable<Double>() {
public Double call() {
return doSomeLongComputation();
}});
doSomethingElse();
try {
Double result = future.get(2, TimeUnit.SECONDS);
} catch (Exception e) {
// 計算拋出一個異常
}
使用 CompletableFuture 構建異步應用
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
}, executorService);
System.out.println("主線程: " + Thread.currentThread().getName());
future.get(2, TimeUnit.SECONDS);
結果:
主線程: main
pool-1-thread-1
(2)supplyAsync方法: 異步創建一個有返回值的CompleteFuture
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService);
System.out.println("主線程: " + Thread.currentThread().getName());
Integer integer = future.get(2, TimeUnit.SECONDS);
System.out.println(integer);
結果:
主線程: main
pool-1-thread-1
4
(3)thenApply, thenAccept, thenRun,這三個都是同步操作
thenApply() 監聽future返回,調用Future方法對返回值業務邏輯操作,這個操作有返回值,比如轉換類型
thenAccept() 監聽future返回,調用Consumer處理返回值,處理的結果沒有返回值,比如打印結果,返回值爲CompletableFuture<void>
thenRun() 監聽future返回,然後自己自定義處理,返回值爲CompletableFuture<void>
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenApply(f ->{
System.out.println(Thread.currentThread().getName());
System.out.println("thenApply: + " + f);
return String.valueOf(f) + "aaa";
});
CompletableFuture<Void> voidCompletableFuture = future.thenAccept(f -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenAccept: + " + f);
});
CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRun(() -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenRun: + ");
});
System.out.println("主線程: " + Thread.currentThread().getName());
String integer = future.get(2, TimeUnit.SECONDS);
System.out.println(integer);
pool-1-thread-1
主線程: main
pool-1-thread-1
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
pool-1-thread-1
thenRun: +
4aaa
(4)thenApplyAsync, thenAcceptAsync, thenRunAsync,同上面三個對應,是異步操作
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenApplyAsync(f ->{
System.out.println(Thread.currentThread().getName());
System.out.println("thenApply: + " + f);
return String.valueOf(f) + "aaa";
}, executorService);
CompletableFuture<Void> voidCompletableFuture = future.thenAcceptAsync(f -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenAccept: + " + f);
}, executorService);
CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRunAsync(() -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenRun: + ");
}, executorService);
System.out.println("主線程: " + Thread.currentThread().getName());
String integer = future.get(2, TimeUnit.SECONDS);
System.out.println(integer);
pool-1-thread-1
pool-1-thread-1
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
主線程: main
pool-1-thread-1
thenRun: +
4aaa
注意:這裏是同一個線程,主要是因爲這裏線程池我用的是可緩存的線程池,線程池爲無限大,當執行第二個任務時第一個任務已經完成,會複用執行第一個任務的線程,而不用每次新建線程。我們可以讓線程睡眠一點時間
修改下代碼:
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenApplyAsync(f ->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
System.out.println("thenApply: + " + f);
return String.valueOf(f) + "aaa";
}, executorService);
CompletableFuture<Void> voidCompletableFuture = future.thenAcceptAsync(f -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
System.out.println("thenAccept: + " + f);
}, executorService);
CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRunAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
System.out.println("thenRun: + ");
}, executorService);
System.out.println("主線程: " + Thread.currentThread().getName());
String integer = future.get(4, TimeUnit.SECONDS);
voidCompletableFuture.get();
voidCompletableFuture1.get();
System.out.println(integer);
主線程: main
pool-1-thread-1
pool-1-thread-2
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
pool-1-thread-2
thenRun: +
4aaa
可以看到還是存在有些線程已經完成並且被複用了,可以再試試把睡眠時間調整爲不一樣試試。
(3) thenCompose方法 多層結構的future返回一個結果,跟java8的flatmap差不多
CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenCompose(f -> CompletableFuture.supplyAsync(() -> f + "dddd", executorService));
System.out.println(stringCompletableFuture.get());
pool-1-thread-2
4dddd
(4)thenCombine與thenAcceptBoth, 合併兩個future,thenCombine有返回值,thenAcceptBoth沒有返回值
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService);
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 5;
}, executorService);
CompletableFuture<Integer> f3 = f1.thenCombine(f2, (s1, s2) -> {
System.out.println(String.format("%d,%d", s1, s2));
return s1 + s2;
});
System.out.println(f3.get());
CompletableFuture<Void> f4 = f1.thenAcceptBoth(f2, (s1, s2) -> {
System.out.println(String.format("%d,%d", s1, s2));
});
System.out.println(f4.get());
pool-1-thread-1
pool-1-thread-2
4,5
9
4,5
null
(5) allOf anyOf
allOf CompleteableFuture數組裏面全部完成才返回結果
ExecutorService executorService = Executors.newCachedThreadPool();
List<CompletableFuture<String>> list = IntStream.rangeClosed(0, 10).mapToObj(i -> CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "sleep :" + i * 1000 + "s");
return i + "s";
}, executorService)).collect(Collectors.toList());
CompletableFuture<Void> f1 = CompletableFuture.allOf(list.toArray(new CompletableFuture[]{}));
System.out.println("全部已經完成了!!" + f1.get());
pool-1-thread-1sleep :0s
pool-1-thread-2sleep :1000s
pool-1-thread-3sleep :2000s
pool-1-thread-4sleep :3000s
pool-1-thread-5sleep :4000s
pool-1-thread-6sleep :5000s
pool-1-thread-7sleep :6000s
pool-1-thread-8sleep :7000s
pool-1-thread-9sleep :8000s
pool-1-thread-10sleep :9000s
pool-1-thread-11sleep :10000s
全部已經完成了!!null
anyOf CompleteableFuture數組裏面其中一個完成就返回結果
ExecutorService executorService = Executors.newCachedThreadPool();
List<CompletableFuture<String>> list = IntStream.rangeClosed(0, 10).mapToObj(i -> CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "sleep :" + i * 1000 + "s");
return i + "s";
}, executorService)).collect(Collectors.toList());
CompletableFuture<Object> f1 = CompletableFuture.anyOf(list.toArray(new CompletableFuture[]{}));
System.out.println("其中一個已經完成了!!" + f1.get());
pool-1-thread-1sleep :0s
其中一個已經完成了!!0s