자바에서 비동기(Asynchronous) 프로그래밍을 가능케하는 인터페이스.
Completable 이란 이름이 붙은 이유는 외부에서 Complete을 시킬 수 있기 때문이다.
Future를 외부에서 완료 시킬 수 없다.
여러 Future를 조합할 수 없다.
리턴 값이 없는 경우: runAsync()
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
});
future.get();
}
// ForkJoinPool.commonPool-worker-19
리턴 값이 있는 경우: supplyAsync()
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "Hong";
});
System.out.println(future.get());
}
// ForkJoinPool.commonPool-worker-19
// Hong
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "Hong";
}).thenApply(s -> {
System.out.println(Thread.currentThread().getName());
return s.toUpperCase();
});
System.out.println(future.get());
}
// ForkJoinPool.commonPool-worker-19
// main
// HONG
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "Hong";
}).thenAccept(s -> {
System.out.println(Thread.currentThread().getName());
});
future.get();
}
// ForkJoinPool.commonPool-worker-19
// main
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "Hong";
}).thenRun(() -> {
System.out.println(Thread.currentThread().getName());
});
future.get();
}
// ForkJoinPool.commonPool-worker-19
// main
ForkJoinPool은 하나의 작업 큐를 가지며 ForkJoinPool에서 관리되는 여러 쓰레드는 Parent 작업에서 분기된 Child 작업을 처리하고(Fork) 각 쓰레드에서 처리된 결과를 합쳐 Parent에게 전달해서(Join) 병렬적으로 작업을 처리하는 프레임워크다.
그렇기 때문에 쓰레드 풀을 만들지 않고도 별도의 쓰레드가 작업을 처리해 주어서 비동기 작업이 가능하다.
원한다면 직접 쓰레드 풀을 생성해서 runAsync, supplyAsync의 두 번째 인자로 넘겨주면 해당 쓰레드 풀을 CompletableFuture의 작업 쓰레드 풀로 사용할 수 있다.
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "Hong";
}, executorService);
System.out.println(future.get());
executorService.shutdown();
}
// pool-1-thread-1
// Hong
콜백 메서드도 별도의 쓰레드 풀에서 실행할 수 있다.
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "Hong";
}, executorService).thenApplyAsync(s -> {
System.out.println(Thread.currentThread().getName());
return s.toUpperCase();
}, executorService);
System.out.println(future.get());
executorService.shutdown();
}
// pool-1-thread-1
// pool-1-thread-1
// HONG