JAVA/JAVA8 관련

CompletableFuture2

JUMP개발자 2022. 5. 31. 16:54

CompletableFuture는 별다른 Executor를 사용하지 않아도 ForkJoinPool에 있는 Common Pool을 사용한다.

하지만 원한다면 직접 쓰레드풀을 만들어서 사용할 수 있다.  아래 예제와 같이 runAsync()나 supplyAsync() 메서드를 호출할 때 2번째 인자로 줄 수 있다. 콜백을 실행할 풀을 다른곳에서 실행할때에는 thenRunAsync, thenAcceptAsync, thenRunAsync 등을 사용하면된다.

public class CompletableFutureP2 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		  ExecutorService executorService = Executors.newFixedThreadPool(4);
	        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
	            System.out.println("Thread1 :: " + Thread.currentThread().getName());
	            return "Hello";
	        }, executorService).thenRunAsync(() -> {
	            System.out.println("Thread2 :: " + Thread.currentThread().getName());
	        }, executorService);

	        future.get();
	        executorService.shutdown();	
	}
}

조합하기

thenCompose() : 두작업이 서로 이어서 실행되도록 한다. 두 작업이 서로 연관관계가 있을 때 사용함.

public class CompletableFutureP3 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		CompletableFuture<String> hello = CompletableFuture.supplyAsync(() -> {
            System.out.println("HI " + Thread.currentThread().getName());
            return "HI";
        });

        CompletableFuture<String> future = hello.thenCompose(CompletableFutureP3::getWorld);
        System.out.println(future.get());
	}
	private static CompletableFuture<String> getWorld(String message) {
    	return CompletableFuture.supplyAsync(() -> {
        		System.out.println("THERE : " + Thread.currentThread().getName());
        		return message + " THERE";
    	});
	}
}

thenCombine() : 독립적인 두작업을 실행하고 둘 다 종료됬을 때 콜백을 실행한다. 

두 작업이 서로 연관관계가 없어 모두 완료된 결과를 바탕으로 추가 작업을 하고 싶을 때 사용한다.

public class CompletableFutureP4 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		CompletableFuture<String> hi = CompletableFuture.supplyAsync(() -> {
            System.out.println("HI " + Thread.currentThread().getName());
            return "HI";
        });

        CompletableFuture<String> there = CompletableFuture.supplyAsync(() -> {
            System.out.println("THERE : " + Thread.currentThread().getName());
            return "THERE";
        });

        CompletableFuture<String> future = hi.thenCombine(there, (h, w) -> h + " " + w); // BiFunction
        System.out.println(future.get());
	}
}

allOf() : 여러작업을 실행하고 모든 작업 결과에 콜백을 실행.

anyOf() : 여러작업 중에 가장 빨리 끝난 결과의 콜백을 실행.

 

예외처리하기

exceptionally(function)

public class CompletableFutureP6 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		 boolean throwError = true;
	        CompletableFuture<String> hi = CompletableFuture.supplyAsync(() -> {
	            if(throwError) {
	                throw new IllegalArgumentException();
	            }
	            System.out.println("hi " + Thread.currentThread().getName());
	            return "hi";
	        }).exceptionally(ex -> {
	            System.out.println(ex);
	            return "Error!";
	        });
	}
}

handle(function) : 첫번째 파라메터는 정상적인 결과의 경우 결과값, 두번째 파라메터는 예외 발생 시 에러를 넣어서 처리함. 즉 정상일 경우와 에러 발생 경우를 모두 처리가능함.

public class CompletableFutureP7 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		 boolean throwError = true;
	        CompletableFuture<String> hi = CompletableFuture.supplyAsync(() -> {
	            if(throwError) {
	                throw new IllegalArgumentException();
	            }
	            System.out.println("Hi " + Thread.currentThread().getName());
	            return "Hi";
	        }).handle((result, error) -> {
	            if(error != null) {
	                System.out.println(error);
	                return "ERROR!!!!!!!";
	            }
	            return result;
	        });
	}
}