Java & Spring/Java

Java - 비동기 처리(ExecutorService / Future)

DJ.Kang 2025. 3. 4. 06:47

□ ExecutorService 정의

  • 여러 개의 스레드를 효율적으로 관리하고 재사용할 수 있도록 돕는 스레드 풀(Thread Pool) 관리 인터페이스
  • submit() 또는 execute()를 통해 작업을 실행할 수 있다.
  • 작업을 실행하면 Future<T> 객체를 반환하여 결과를 받을 수 있다.

 

Future 정의

  • ExecutorService.submit() 메서드를 호출하면 작업의 결과를 받을 수 있는 Future<T> 객체가 반환된다.
  • future.get()을 호출하면 결과를 가져올 수 있지만, 결과가 준비될 때까지 블로킹(대기) 된다.
  • 작업을 취소할 수도 있다 → future.cancel(true)

 

□ 장점

  • 스레드 풀(Thread Pool)을 관리하면서 비동기 작업을 효율적으로 수행

 

□ 단점

  • 블로킹 방식이므로 결과를 기다려야 할 수 있음

□ 실습코드

- 간단한 연산 메서드

private static double plus() throws InterruptedException {
        final long startTime = System.currentTimeMillis();
        double a = Math.round(random() * 10);
        double b = Math.round(random() * 10);
        double plus = a + b;
        Thread.sleep(100);
        log.info("{}, 소요시간: {}", plus, System.currentTimeMillis() - startTime);
        return plus;
    }

 

- get()없이 비동기 실행

public static void main(String[] args) {
        final ExecutorService executorService = Executors.newCachedThreadPool();
        final long startTime = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            executorService.submit(
                    () -> plus()
            );
        }
        log.info("메인 스레드 실행 소요시간: {}", System.currentTimeMillis() - startTime);
    }

  • 메인스레드가 우선적으로 실행됨
  • 정해진 스레드풀의 크기에서 재활용하지만 재활용 시 시간이 소요됨

- get()을 통해 비동기 작업의 값을 받아오려고 할 때

public static void main(String[] args) throws ExecutionException, InterruptedException {
        final ExecutorService executorService = Executors.newCachedThreadPool();
        final long startTime = System.currentTimeMillis();
        for(int i = 0; i < 5; i++){
            int finalI = i;
            Future<Double> future = executorService.submit(
                    () -> plus()
            );
            log.info(String.valueOf(future.get()));
        }
        log.info("메인 스레드 실행 소요시간: {}", System.currentTimeMillis() - startTime);
        Thread.sleep(3000);
        executorService.shutdown();
    }

  • 각 작업이 비동기로 실행됨
  • get()으로 인해 메인 스레드 실행 소요시간이 늦어짐