hyeonga_code

Project_14_CompletableFuture는 무엇인가 본문

Project_HYEONGARL

Project_14_CompletableFuture는 무엇인가

hyeonga 2024. 6. 25. 05:59
반응형

 

 

CompletableFuture (Java SE 22 & JDK 22)

JavaScript is disabled on your browser. Nested Class Summary Nested Classes Nested classes/interfaces declared in interface java.util.concurrent.Future Future.State Constructor Summary Constructors Method Summary All MethodsStatic MethodsInstance MethodsC

docs.oracle.com

 

 

CompletableFuture의 기본 개념

+ 별도의 스레드에서 비동기적으로 작업을 수행할 수 있다.

+ 작업이 완료된 후 실행할 콜백 함수를 등록할 수 있다.    

+ 여러 비동기 작업의 결과를 조합할 수 있다.                  

+ 비동기 작업 중 발생한 예외를 처리할 수 있다.              

 

 



java.util.concurrent.CompletableFuture<T>

CompletableFuture<T>


Java 8에서 추가된 비동기 프로그래밍을 위한 클래스다.

Future  Future<T>,  CompletionStage<T> 인터페이스를 구현하여 비동기 작업의 완료 상태를 나타낸다.

비동기 작업을 처리하고 결과를 기다리거나 콜백을 설정할 수 있다.

즉 비동기 작업을 외부에서 완료시킬 수 있다.

'몇 초 이내에 응답이 없는 경우 기본 값을 반환한다'와 같은 기능을 설정할 수 있다.

 

 

 

 

Future(value/status)로 사용된다.

 

비동기 메소드의 종속 완료를 위해 제공된 작업은 다음과 같은 스레드에서 수행할 수 있다.

CompletableFuture 또는 다른 호출자에 의해 완료되는 완성 메소드이다.

 

Executor

명시적인 Executor 를 매개변수로 받지 않는 경우

모든 비동기 메소드의 인수는 ForkJoinPool.commonPool()을 사용하여 작업을 수행한다.

이를 통해 작업이 병렬로 실행될 수 있으며, 최소 2의 병렬 처리를 지원하지 않는 경우 각 작업을 실행하기 위해 새로운 스레드가 생성된다.

 

 

추적/디버깅

비동기 작업을 추적하고 디버깅하기 위해 CompletableFuture.AsynchronousCompletionTask 마커 인터페이스가 사용된다.


CompletableFuture.AsynchronousCompletionTask 인터페이스

메소드에 의해 생성된 비동기 작업을 식별하는 표식 인터페이스
모니터링에 유용하다.
디버깅 및 비동기 활동을 추적한다.

 

 

 

지연/시간 제한

지연 및 시간 제한이 있는 메소드를 지원하기 위해 최대 하나의 데몬 스레드를 유지 관리한다.

supplyAsync(supplier, delayedExecutor(timeout, timeUnit))

 

 

 

 

CompletableFuture는 CompletionStage를 구현하여 다양한 비동기 작업을 처리하고 결과를 조합/처리할 수 있다.

CompletionStage 인터페이스의 모든 메소드는 다른 공용 메소드로 메소드의 동작이 다른 메소드의 동작에 영향을 미치지 않도록 설계되었다.

 

CompletionStage 의 모든 메소드는 CompletableFuture를 반환하므로 체이닝을 통해 여러 비동기 작업을 연속적으로 연결할 수 있다.

 

minimalCompletionStage()

CompletableFuture가 완료된 후에 CompletionStage를 반환한다.

최소한의 기능만 제공하는 CompletionStage를 반환하여 불필요한 기능을 줄이고 더 간단하게 사용할 수 있다.

 

 

 

 

CompletionException이 있는 예외 완료의 경우 get(), get(long, TimeUmit)은 해당 CompletionException

CompletionException을 직접 던지는 join() 이나 getNow(T) 메소드를 정의한다.

 

 

 

 

CompletableFuture<T> 의 주요 메소드

1. 비동기 작업 실행 메소드
- supplyAsync
- runAsync

2. 콜백 메소드
- thenApply
- thenAccept
- thenRun
- thenCompose
- thenCombine

3. 예외 처리 메소드
- exceptionally
- handle

4. 지연된 실행 시간과 시간 제한
- delayedExecutor
- orTimeout

5. 완료 상태 확인 및 직접 완료 메소드
- isCompletedExceptionally
- completeExceptionally
- complete
- join
- get

 

 

1. 비동기 작업 실행 메소드

supplyAsync()

반환값이 있는 비동기 작업을 실행한다.

/**
	U 	: 함수의 반환 유형
    supplier 	: CompletableFuture를 완료하기 위해 반환하는 함수
    executor	: 비동기 실행에 사용할 실행자
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

 

비동기적으로 완료된 새로운 CompletableFuture를 반환한다.

ForkJoinPool.commonPool()에서 실행되는 작업에 위해 지정된 Supplier를 호출하여 얻은 값을 의미한다.

원하는 스레드풀을 사용하려면 ExecutorService를 파라미터로 넘긴다.

얻은 값으로 주어진 실행자에서 실행되는 작업에 의해 주어진 공급자를 호출한다.

supplier 타입을 넘기므로 반환 값이 존재한다.

 

더보기
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 작업 수행 
    return "Hello Java!";
});

 

 

runAsync()

반환값이 없는 비동기 작업을 실행한다.

/**
    runnable	: 완료하기 전에 실행할 작업을 반환
    executor	: 비동기 실행에 사용할 실행자
*/
public static CompletableFuture<Void> runAsync(Runnable runnable)

public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

 

비동기적으로 완료된 새로운 CompletableFuture를 반환한다.

주어진 실행자에서 실행되는 작업에 의해 실행자를 실행한 후에 행동한다.

Runnable 타입을 파라미터로 전달하므로 어떤 결과 값을 담지 않는다.

 

더보기
CompletableFuture<String> future = CompletableFuture.runAsync(() -> {
    // 작업 수행
});

 

 

 

2. 콜백 메소드

비동기 실행이 끝난 후 체이닝 형태로 작성하여 전달 받은 작업 콜백을 실행한다.

 

.thenApply

작업이 완료된 후 결과를 처리한다.

반환 값을 받아 다른 값을 반환한다.
함수형 인터페이스 Function을 파라미터로 받는다.


.thenApplyAsync

앞선 계산의 결과를 콜백 함수로 전달된 Function을 별도의 스레드에서 비동기적으로 실행한다.

CompletableFuture<String> future3 = future2.thenApply(result -> result + " Modified");

 

 

.thenAccept

작업이 완료된 후 결과를 소비한다.

반환 값을 받아 처리하고 값을 반환하지 않는다.
함수형 인터페이스 Consumer를 파라미터로 받는다.

 

.thenAcceptAsync

앞선 계산의 결과를 콜백 함수로 전달된 Consumer를 별도의 스레드에서 비동기적으로 실행한다.

CompletableFuture<Void> future = future2.thenAccept(result -> System.out.println(result));

 

 

.thenRun

작업이 완료된 후 추가 작업을 실행한다.

반환 값을 받지 않고 다른 작업을 실행한다.
함수형 인터페이스 Runnatble을 파라미터로 받는다.


.thenRunAsync

앞선 계산의 결과와 상관없이 주어진 작업을 별도의 스레드에서 비동기적으로 실행한다.

CompletableFuture<Void> future = future2.thenRun(() -> System.out.println("Done"));

 

 

.thenCompose

작업의 결과를 다른 비동기 작업으로 연결한다.

두 작업이 이어서 실행하도록 조합하며 앞선 작업의 결과를 받아 사용한다.

함수형 인터페이스 Function을 파라미터로 받는다.

CompletableFuture<String> future = future2.thenCompose(result ->
    CompleatbleFuture.supplyAsync(() -> result + " Chained")
);

 

 

.thenCombine

두 비동기 작업의 결과를 조합한다.

두 작업을 독립적으로 실행하고 둘 다 완료된 경우 콜백을 실행한다.
함수형 인터페이스 Function을 파라미터로 받는다.

CompletableFuture<String> future = future2.thenCombine(future3, (result1, result2) ->
    result1 + " " + result2;
);

 

 

 

 

 

 

3. 예외 처리 메소드

.exceptionally

예외 발생 시 대체 값을 제공한다.

발생한 에러를 받아 예외를 처리한다.
함수형 인터페이스 Function을 파라미터로 받는다.

CompletableFuture<String> future = future2.exceptionally(ex -> "Default Value");

 

 

.handle

예외 발생 여부와 관계없이 결과나 예외를 처리한다.

결과값,에러를 반환받아 에러가 발생한 경우와 아닌 경우 모두를 처리할 수 있다.
함수형 인터페이스 BiFunction을 파라미터로 받는다.

CompletableFuture<String> future = future2.handle((result, ex) -> {
    if(ex != null) {
        return "Default Value";
    }
    return result;
});

 

 

 

 

4. 지연된 실행 시간과 시간 제한

.delayedExecutor

지연된 Executor를 사용하여 비동기 작업을 수행한다.

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> 
    "Hello", CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)
);

 

 

.orTimeout

시간 제한을 설정하여 비동기 작업을 수행한다.

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> 
    "Hello", CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)
).orTimeout(2, TimeUnit.SECONDS);

 

 

 

5. 완료 상태 확인 및 직접 완료 메소드

FutureTask와 다르게 직접 계산이 완료되도록 제어하거나 취소할 수 있다.

제어나 취소는 예외의 또 다른 형태로 처리된다.

예외적인 완료 상태를 확인하고 필요한 경우 예외를 발생시킬 수 있다.

 

.isCompletedExceptionally

예외로 인해 완료되었는지 확인한다.

boolean completedExceptionally = future.isCompletedExceptionally();

 

 

.completeExceptionally

작업을 예외로 완료시킨다.

future.completeExceptionally(new CancellationException("Canceled"));

 

 

.complete

특정 결과로 작업을 완료한다.

future.complete("Completion");

 

 

.join

작업이 완료될 때까지 기다려 결과를 반환한다.

CompletableFuture에 정의되어 있다.

Checked Exception을 발생시키지 않으나 UnChecked Exception이 발생한다.

일반적으로 권장되나 예외 처리에 대한 추가 로직이 필요한 경우나 timeout을 설정을 해야 하는 경우 get() 을 사용한다.

String result = future.join();

 

 

.get

예외가 포함된 완료의 경우 Exception을 던진다.

Future 인터페이스에 정의되어 있다.

Checked Exception의 InterruptedException/ExecutionException을 던지므로 예외처리 로직이 반드시 필요하다.

try {
    String result = future.get()
} catch (ExecutionException | InterruptedException e) {
    // 예외 처리
}

 

 

 

 

 

 

CompletionException 처리

CompletionException이 있는 예외 완료의 경우 get() / get(long, TimeUnit) 메소드는 CompletionException 을 래핑하여 던진다.

join() / getNow(T) 메소드는 CompletionException 을 직접 던진다.

 

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    throw new CompletionException(new RuntimeException("Exception"));
});

try {
    // ExecutionException을 던지고, 그 내부에 CompletionException이 래핑됨
    future.get(); 
} catch (ExecutionException | InterruptedException e) {
    Throwable cause = e.getCause();
    if (cause instanceof CompletionException) {
        // Handle CompletionException
    }
}

try {
    // CompletionException을 직접 던짐
    future.join(); 
} catch (CompletionException e) {
    // Handle CompletionException
}

// 완료되지 않은 경우 기본값 반환, 예외 발생 시 CompletionException 던짐
String result = future.getNow("Default Value");

 

 

 

.acceptEither / .acceptEitherAsync

1)

CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)

두 개 중 하나라도 정상적으로 완료되면 결과를 매개변수로 제공하는 새로운 CompletionStage 를 반환한다.

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> " Java");

future1.acceptEither(future2, System.out::println);

 

 

2)

CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action [, Executor executor])

두 개  중 하나라도 정상적으로 완료되면 기본 비동기 실행자를 사용하여 해당 결과를 매개변수로 제공하는 액션을 실행하는 새로운 CompletionStage 를 반환한다.

future1.acceptEitherAsync(future2, System.out.::println);

 

 

.allOf / .anyOf

1)

static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)

주어진 모든 CompletableFuture가 완료되면 완료되는 새로운 CompletableFuture 를 반환한다.

여러 작업을 동시에 실행하고 모든 작업 결과에 콜백을 실행한다.

CompletableFuture<Void> allFuture = CompletableFuture.allOf(future1, future2);

// 모든 future가 완료될 때까지 기다린다.
allFuture.join();

 

 

2)

static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)

주어진 CompletableFuture 중 하나라도 완료되면 동일한 결과로 완료되는 새로운 CompletableFuture 를 반환한다.

여러 작업들 중 가장 빨리 끝난 하나의 결과에 콜백을 실행한다.

CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);

// 하나의 future가 완료되면 결과를 출력한다.
anyFuture.thenAccept(System.out::println);

 

 

.applyToEither

1)

<U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T,U> fn)

둘 중 하나라도 정상적으로 완료되면 해당 결과를 매개변수로 제공된 함수를 실행하여 CompletionStage 를 반환한다.

CompletableFuture<Integer> future3 = future1.applyToEither(future2, String::length);

 

 

2)

<U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn  [, Executor executor])

둘 중 하나라도 정상적으로 완료되면 해당 결과를 매개변수로 제공된 함수를 기본 비동기 실행자를 사용하여 실행한다.

CompletableFuture<Integer> future3 = future1.applyToEitherAsync(future2, String::length);
CompletableFuture<Integer> future3 = future1.applyToEitherAsync(future2, String::length, executor);

 

 

 

.complete/ .completeAsync/ .completedFuture

1)

boolean complete(T value)

이미 완료되지 않은 경우 제공된 value로 CompletableFuture 를 완료한다.

future.complete("Completed");

 

 

2)

CompletableFuture<T> completeAsync(Supplier<? extends T> supplier)

기본 실행자를 사용하여 비동기 작업에서 제공된 Supplier 함수를 호출하여 CompletableFuture 를 완료한다.

future.completeAsync(() -> "Async Completed");

 

 

3)

static <U> CompletableFuture<U> completedFuture(U value)

주어진 값으로 이미 완료된 새로운 CompletableFuture 를 반환한다.

CompletalbeFuture<String> completedFuture = CompletableFuture.completedFuture("Completed");

 

 

.isDone()

CompletableFuture 가 완료되었는지 여부를 반환한다.

 

.obtrudeValue(T value)

CompletableFuture 의 결과를 강제로 설정한다.

 

.obtrudeException(Throwable ex)

CompletableFuture 의 결과를 강제로 예외로 설정한다.

 

.toString()

CompletableFuture 를 나타내는 문자열과 완료 상태를 반환한다.

 

.toCompletableFuture

CompletableFuture 를 반환한다.



 

 


https://www.baeldung.com/java-completablefuture

 

Java의 비동기 계산

모든 계산을 일련의 단계로 생각하고 싶으나 비동기 계산의 경우 콜백으로 표현되는 작업은 코드 전체에 흩어져 있거나 서로 중첩되는 경향이 있다. > 단계중 하나에서 발생할 수 있는 오류를 처리해야 하는 경우 상황이 더욱 복잡해진다.

 

Future 인터페이스는 비동기 계산의 결과로 사용하기 위해 Java5 에 추가되었으나 계산을 결합하거나 오류를 처리하는 메소드가 없었다.

 

CompletableFuture 클래스는 다른 단계와 결합할 수 있는 비동기 계산 단계에 대한 작업을 정의한다.

 

 

 

+ 단순 Future로 사용

인수가 없는 생성자를 사용하여 클래스의 인스턴스를 만들어 Future의 결과를 나타내고 클라이언트에게 전달하여 complete() 메소드를 사용하여 지정 시점에 완료할 수 있다. 클라이언트는 get() 메소드를 사용하여 결과가 제공될 때까지 현재 스레드를 차단할 수 있다.

 

CompletableFuture 인스턴스를 생성하고 다른 스레드에서 일부 계산을 스핀 오프하고 Future를 즉시 반환하는 메소드가 있다. 계산이 완료되면 complete() 메소드에 결과를 제공하여 Future를 완성한다.

public Future<String> calculateAsync() throws InterruptedException {
    CompletableFuture<String> completableFuture = new CompletableFuture<>();
    
    Executors.newCachedThreadPool().submit(() -> {
        Thread.sleep(500);
        compleatbleFuture.complete("Hello");
        return null;
    });
    
    return completableFuture;
}

 

 

 

Future<String> completableFuture = calculateAsync();
...
String result = completableFuture.get();
assertEquals("Hello", result);

 

get 메소드의 예외

ExecutionException : 계산 중 발생한 예외의 캡슐화

InterruptedException : 작업 전/중 스레드가 중단되는 예외

 

 

Future<String> completableFuture 
    = CompletableFuture.completedFuture("Hello");
...
String result = completableFuture.get();
assertEquals("Hello", result);

 

계산 결과를 이미 알고 있는 경우 매개변수와 함께 메소드를 사용할 수 있다.

 

 

 

+ 캡슐화된 CompletableFuture

상용구를 건너뛰고 일부 코드를 비동기적으로 실행하려면?

Runnable/Supplier 는 새로운 Java 8 기능으로 인스턴스를 람다 표현식으로 전달할 수 있는 기능적 인터페이스다.

 

Runnable 인터페이스 : 스레드에서 사용되는 것과 동일한 이전 인터페이스로 값을 반환할 수 없다.

Supplier 인터페이스 : 인수가 없고 매개변수가 있는 형식의 값을 반환하는 단일 메소드가 있는 제네릭 함수 인터페이스다.

 

Completablefuture<String> future 
    = CompletableFuture.supplyAsync(() -> "Hello");
...
assertEquals("Hello", future.get());

 

 

 

 

+ 비동기 계산의 결과 처리

계산 결과를 함수에 제공하는 것이 가장 일반적인 계산 결과를 처리하는 방법이다.

CompletableFuture<String> completableFuture 
    = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future 
    = completableFuture.thenApply(s -> s + " World");

assertEquals("Hello World", future.get());

 

반환할 값이 없는 경우 Void를 반환한다.

 

계산 값이 필요하지 않거나 체인 끝에 일부 값을 반환하고 싶지 않은 경우 Runnable 람다를 사용한다.

CompletableFuture<String> completableFuture 
    = CompletableFuture.suuplyAsync(() -> "Hello");
CompletableFuture<Void> future 
    = completableFuture.thenRun(() -> System.out.println("Computation finished."));

future.get();

 

 

 

+ 결합

계산 단계 체인에서 결합할 수 있다.

동일한 유형의 다른 객체를 반환하는 함수를 받는다.

이전 계산 단계의 결과를 받아 다음 Future의 매개 변수로 사용한다.

CompletableFuture<String> completableFuture
    = CompletableFuture.supplyAsync(() -> "Hello")
        .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World");
        
assertEquals("Hello World", completableFuture.get());

 

 

 

두 개의 독립적인 Future를 실행하고 결과로 수행을 하려는 경우 thenCombine을 사용한다.

CompletableFuture<String> completableFuture
    = CompletableFuture.supplyAsync(() -> "Hello")
        .thenCombine(
            CompletableFuture.supplyAsync(() -> " World"), 
            (s1, s2) -> s1 + s2)
        );
        
assertEquals("Hello World", completableFuture.get());

 

 

결과 값을 Future 체인 아래로 전달할 필요가 없는 경우

CompletableFuture future 
    = CompletableFuture.supplyAsync(() -> "Hello")
        .thenAcceptBoth(CompletableFuture.supplyAsync(() -> " World"),
            (s1, s2) -> System.out.println(s1 + s2)
        );

 

 

.thenApply() 와 .thenCompose() 차이점

thenApply() : 이전 호출의 결과로 작업할 수 있으므로 호출의 결과를 변환하는 경우 유용하다.

thenCompose() : 이전 호출의 결과를 인수로 사용한다.

CompletableFuture<Integer> computAnother(Integer i) {
    return CompletableFuture.supplyAsync(() -> 10 + i);
}

CompletableFuture<Integer> finalResult = compute().thenCompose(this::computeAnother);

 

 

 

 

+ 여러 Future를 병렬로 실행

일반적으로 모든 Future가 실행될 때까지 기다렸다가 결합된 결과를 처리하려고 한다.

.allOf 정적 메소드는 모든 Futures가 완료될 때까지 기다린다.

CompletableFuture<String> future1
    = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2
    = CompletableFuture.supplyAsync(() -> " Beautiful");
CompletableFuture<String> future3
    = CompletableFuture.supplyAsync(() -> " World");
  
CompletableFuture<Void> combinedFuture
    = CompletableFuture.allOf(future1, future2, future3);
    
...

combinedFuture.get();
assertTrue(future1.isDone());
assertTrue(future2.isDone());
assertTrue(future3.isDone());

 

 

join() 메소드를 사용하면 간단하게 작성할 수 있다.

String combined 
    = Stream.of(future1, future2, future3)
        .map(CompletableFuture::join)
        .collect(Collectors.joinint(" "));
        
assertEquals("Hello Beautiful World", combined);

 

 

+ 오류 처리

throw/catch 관용구를 비슷한 방식으로 작성한다.

핸들 메소드에서 예외를 처리할 수 있다. 계산 결과와 throw된 예외라는 매개 변수를 받는다.

String name = null;

CompletableFuture<String> completableFuture
    = CompletableFuture.supplyAsync(() -> {
        if(name == null) {
            throw new RuntimeException("Error");
        }
        return "Hello, " + name;
    }).handle((s, t) -> s != null ? s : "Hello, Stranger");
    
assertEquals("Hello, Stranger", completableFuture.get());

 

 

Future를 수동으로 완료할 때 예외를 제외하고 완료할 수 있다.

CompletableFuture<String> completableFuture
    = new CompletableFuture<>();
    
completableFuture.completeExceptionally(new RuntimeException("Fail"));

completable.get();

 

 

 

+ 비동기 메소드

다른 스레드에서 해당 실행 단계를 실행하기 위한 것이다.

CompletableFuture<String> completableFuture
    = CompletableFuture.supplyAsync(() -> "Hello");
    
CompletableFuture<String> future
    = completableFuture.thenApplyAsync(s -> s + " World");
    
assertEquals("Hello World", future.get());

 

 


Future


java.util.concurrncy

 

비동기 작업의 결과 값을 받는 용도로 사용했으나 결과를 조합하거나 예외를 효과적으로 처리할 수 없었다.

get 호출로만 작업을 종료할 수 있어 작업이 완료될 때까지 대기하는 블로킹으로 비동기 작업 응답에 추가적으로 작업을 할 수 없어 나온 것이 CompletableFuture다.

 

get() : 작업이 완료될 때까지 대기한다.

get(Long timeout, TimeUnit unit) : 작업이 완료될 때까지 설정한 시간 동안 대기하며 시간 내 작업을 완료하지 못한 경우 TimeoutException이 발생한다.

 

 

CompletionStage

계산의 완료됨을 의미하는 약속이다.

계산의 완료는 단일 단계의 완료뿐 아니라 다른 여러 단계 혹은 다른 여러 단계 중의 하나로 이어질 수 있음도 포함한다.

각 단계에서 발생한 에러를 관리하고 전달할 수 있다.

Completable은 외부에서 명시적으로 Complete할 수 있다.

몇 초 이내에 응답이 오지 않는 경우 기본값으로 미리 캐시해둔 값이나 특정 값을 리턴할 수 있다.

 

 

CompletableFutre를 사용하면

더 이상 명시적으로 Executor를 만들어 사용할 필요가 없다.

비동기적으로 작업을 실행할 수 있다.

 

 

 

ForkJoinPool

Executor를 구현한 구현체 중 하나로 Java7에 도입되었다.

Work Stealing 알고리즘을 사용하며 다른 Deque를 사용한다.

먼저 들어온게 먼저 나가는 Queue와 다르게 마지막에 들어온 게 먼저 나가는 Deque를 사용한다.

자신의 스레드가 할 일이 없는 경우 스레드가 직접 Deque에서 할 일을 가져와 처리하는 방식의 Framework이다.

 

작업 단위를 자신이 파생시키는 세부적인 sub task를 잘게 쪼개 다른 스레드에 분산시켜 작업을 처리하고 모아 결과를 도출해낸다.

별다른 Executor를 사용하지 않아도 내부적으로 ForkJoinPool 에 있는 commonPool()을 사용하는 것이다.

 

ExecutorService executorService = Executors.newFixedThreadPool(n);
...
exetutorService.shutdown();		//필수

 

 

 


 

 

비동기 처리

특정 작업이 다른 작업과 독립적으로 동작하도록 하여 다음 단계의 작업이 이전 작업의 완료를 기다리지 않고 동시에 실행할 수 있도록 하거나 특정 작업의 완료를 기다리는 동안 다른 작업을 처리할 수 있다.

 

한 작업이 완료되기를 기다렸다가 다음 작업을 순차적으로 실행하는 동기적 처리와 다르게 여러 작업이 동시에 실행될 수 있고 다른 작업의 완료를 기다리지 않고 실행하여 시스템 자원을 최대한 활용할 수 있는 방식이다.

 

비동기 처리를 통해 성능을 향상시키거나 시스템의 활용도를 증가하고 동시성을 관리, 자원 활용 등의 장점이 있다.

그러나 복잡성이 증가하고 디버깅이 어렵고 가독성이 떨어지는 단점을 고려해야 한다.

 

Future 인터페이스는 비동기 연산을 위해 추가되었으나 여러 연산을 결합하기 어렵고, 비동기 처리 중 발생하는 예외 처리하기 어렵다는 문제가 있다. 하여 Future와 CompleteStage를 구현하는 CompletableFuture가 등장했다.

 

Future : 비동기 연산을 위해 추가된 인터페이스

CompleteStage : 여러 연산을 결합할 수 있도록 비동기식 연산 단계를 제공하는 인터페이스

 

Future					CompletableFuture
----------------------------------------------------------------
Blocking				Non-Blocking
여러 연산을 함께 연결하기 어렵다	여러 연산을 함께 연결한다.
여러 연산 결과를 결합하기 어렵다	여러 연산 결과를 결합한다.
예외 처리가 어렵다.			예외 처리가 가능하다.
연산 성공 여부만 확인할 수 있다.
반응형