반응형

비동기 작업에서 Executor를 사용하는 방법은 CompletableFuture의 비동기 작업을 특정 Executor를 통해 실행하도록 설정하는 것입니다. 기본적으로 CompletableFuture.supplyAsyncCompletableFuture.runAsync는 공용 ForkJoinPool의 공용 스레드 풀을 사용하지만, 특정 Executor를 지정하여 사용자 정의 스레드 풀을 사용할 수도 있습니다.

 

Executor를 사용하는 방법

 

1. Executor 생성

 

먼저, 사용할 Executor를 생성해야 합니다. 예를 들어, ExecutorService는 자주 사용되는 Executor 구현 중 하나입니다.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

ExecutorService executor = Executors.newFixedThreadPool(10);

2. CompletableFuture에서 Executor 사용

 

CompletableFuture의 비동기 작업을 시작할 때, Executor를 두 번째 인수로 전달합니다.

 

supplyAsync 사용 예

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureWithExecutorExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 비동기 작업 수행
            return "Hello, World!";
        }, executor);

        future.thenAccept(result -> System.out.println("Result: " + result));

        // Executor 서비스 종료
        executor.shutdown();
    }
}

3. 여러 비동기 작업을 결합하여 Executor 사용

thenApplyAsync, thenAcceptAsync, thenRunAsync 등의 메서드도 Executor를 인수로 받아서 지정할 수 있습니다.

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureWithMultipleAsyncExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        CompletableFuture.supplyAsync(() -> {
            // 첫 번째 비동기 작업
            return "Hello";
        }, executor).thenApplyAsync(result -> {
            // 두 번째 비동기 작업
            return result + ", World!";
        }, executor).thenAcceptAsync(result -> {
            // 세 번째 비동기 작업
            System.out.println("Result: " + result);
        }, executor);

        // Executor 서비스 종료
        executor.shutdown();
    }
}

 

요약

 

1. Executor 생성: ExecutorService와 같은 Executor 구현체를 생성합니다.

ExecutorService executor = Executors.newFixedThreadPool(10);

2. 비동기 작업에서 Executor 사용: supplyAsync, runAsync, thenApplyAsync, thenAcceptAsync, thenRunAsync 등의 메서드에서 Executor를 두 번째 인수로 전달합니다.

CompletableFuture.supplyAsync(() -> "Hello, World!", executor);

3. Executor 서비스 종료: 모든 비동기 작업이 완료되면 executor.shutdown()을 호출하여 Executor를 종료합니다.

executor.shutdown();

 

CompletableFuture Executor

CompletableFutureExecutor를 같이 사용하는 것은 여러 가지 이점을 제공합니다.

이 조합을 사용하면 비동기 작업의 효율성과 유연성을 극대화할 수 있습니다.

주요 이점

 

1. 병렬 처리의 효율성 증가

 

설명: 여러 비동기 작업을 병렬로 처리함으로써 전체 작업의 수행 시간을 단축할 수 있습니다. Executor를 사용하면 특정 스레드 풀을 통해 작업을 분산시켜 병렬 처리의 효율성을 극대화할 수 있습니다.

 

2. 작업 스케줄링 제어

 

설명: Executor를 사용하면 비동기 작업의 실행 정책을 세밀하게 제어할 수 있습니다. 예를 들어, 고정된 수의 스레드 풀, 캐시된 스레드 풀, 단일 스레드 풀 등을 사용하여 작업을 스케줄링할 수 있습니다.

 

3. 리소스 관리

 

설명: Executor를 사용하면 스레드 생성 및 관리를 중앙집중식으로 제어할 수 있어 시스템 리소스를 효율적으로 관리할 수 있습니다. 이를 통해 과도한 스레드 생성으로 인한 성능 저하를 방지할 수 있습니다.

 

4. 작업의 독립성 보장

 

설명: 각 비동기 작업을 별도의 스레드에서 실행하므로 작업 간의 간섭을 최소화할 수 있습니다. 이를 통해 독립적인 작업이 서로 영향을 주지 않고 안전하게 실행될 수 있습니다.

CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
    // 첫 번째 작업
}, executor);
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
    // 두 번째 작업
}, executor);

5. 복잡한 비동기 작업 처리

 

설명: 여러 비동기 작업을 조합하여 복잡한 비동기 워크플로우를 쉽게 구현할 수 있습니다. CompletableFuture의 다양한 메서드를 사용하여 작업 간의 의존성을 설정하고, Executor를 통해 이러한 작업을 효율적으로 처리할 수 있습니다.

 

6. 예외 처리 및 복구

 

설명: 비동기 작업에서 발생하는 예외를 처리하고, 필요시 복구 작업을 수행할 수 있습니다. CompletableFutureexceptionally, handle 메서드와 함께 사용하여 예외 처리를 더 유연하게 할 수 있습니다.

 

종합 예시 코드

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureWithExecutorExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        CompletableFuture.supplyAsync(() -> {
            // 비동기 작업 1
            return "Task 1 result";
        }, executor).thenApplyAsync(result -> {
            // 비동기 작업 2
            return result + " + Task 2 result";
        }, executor).thenAcceptAsync(result -> {
            // 비동기 작업 3
            System.out.println("Final Result: " + result);
        }, executor).exceptionally(ex -> {
            System.err.println("Exception: " + ex);
            return null;
        });

        executor.shutdown();
    }
}

 

요약

기본 스레드 풀: CompletableFutureExecutor와 함께 사용하지 않으면, 기본적으로 ForkJoinPool의 공용 스레드 풀을 사용합니다.

공용 스레드 풀의 크기는 시스템의 가용 프로세서 수에 따라 자동으로 결정됩니다.

반응형

+ Recent posts