Java의 Executor 인터페이스

Executor는 Java의 멀티스레드 프로그래밍을 단순화하기 위해 설계된 인터페이스입니다. 이 인터페이스는 스레드 생성을 개발자가 직접 처리하지 않고, 작업 제출 및 실행을 처리할 수 있도록 추상화된 방법을 제공합니다.


특징

  1. 작업 제출과 실행 전략 분리: Executor를 사용하면 작업을 스레드 풀이나 특정 실행 정책에 맞게 실행할 수 있습니다.
  2. 스레드 관리 최적화: 스레드 풀을 사용하면 스레드의 재사용과 리소스 관리를 효율적으로 처리할 수 있습니다.
  3. 비동기 작업 처리: 작업 실행이 비동기로 처리될 수 있습니다.

Executor 인터페이스 정의

@FunctionalInterface
public interface Executor {
    void execute(Runnable command);
}
  • execute(Runnable command): Runnable 객체를 받아 실행합니다. 작업 실행 방식은 구현에 따라 달라집니다.

Executor의 주요 구현체

  • ThreadPoolExecutor: 스레드 풀을 사용하여 작업을 실행.
  • ScheduledThreadPoolExecutor: 일정한 시간 간격으로 작업을 실행.
  • ForkJoinPool: 작업을 작은 단위로 나누어 병렬 처리.

Executor 사용 예제

1. 간단한 구현

import java.util.concurrent.Executor;

public class SimpleExecutor implements Executor {
    @Override
    public void execute(Runnable command) {
        new Thread(command).start(); // 매번 새로운 스레드를 생성하여 실행
    }

    public static void main(String[] args) {
        Executor executor = new SimpleExecutor();

        // 작업 제출
        executor.execute(() -> System.out.println("Hello from SimpleExecutor!"));
    }
}
  • 설명: SimpleExecutor는 매번 새 스레드를 생성해 작업을 실행합니다.

2. 스레드 풀 사용

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

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 고정 크기 스레드 풀 생성
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 10; i++) {
            int taskId = i;
            executorService.execute(() -> {
                System.out.println("Task " + taskId + " is running in thread " + Thread.currentThread().getName());
            });
        }

        // 스레드 풀 종료
        executorService.shutdown();
    }
}
  • 설명:
    • Executors.newFixedThreadPool(3): 3개의 스레드로 구성된 스레드 풀 생성.
    • execute(): 작업을 스레드 풀에 제출하여 실행.

3. 사용자 정의 스레드 풀

import java.util.concurrent.*;

public class CustomThreadPoolExecutor {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2,               // corePoolSize
            5,               // maximumPoolSize
            60,              // keepAliveTime
            TimeUnit.SECONDS,// keepAliveTime 단위
            new LinkedBlockingQueue<>(10) // 작업 대기열
        );

        for (int i = 0; i < 15; i++) {
            int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
            });
        }

        executor.shutdown();
    }
}
  • 설명:
    • corePoolSize: 기본적으로 유지되는 스레드 수.
    • maximumPoolSize: 최대 생성 가능한 스레드 수.
    • keepAliveTime: 스레드가 사용되지 않을 때 유지되는 시간.

4. ScheduledExecutorService 사용

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorExample {
    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

        // 3초 후에 실행
        scheduler.schedule(() -> System.out.println("Task executed after 3 seconds"), 3, TimeUnit.SECONDS);

        // 2초 주기로 반복 실행
        scheduler.scheduleAtFixedRate(() -> System.out.println("Repeating task"), 1, 2, TimeUnit.SECONDS);

        // 10초 후 스케줄러 종료
        scheduler.schedule(() -> {
            System.out.println("Shutting down scheduler");
            scheduler.shutdown();
        }, 10, TimeUnit.SECONDS);
    }
}
  • 설명:
    • schedule(): 특정 시간 후 작업 실행.
    • scheduleAtFixedRate(): 고정 주기로 작업 반복 실행.

ExecutorServiceExecutor의 차이

  • Executor: 단순히 작업 실행에 대한 API만 제공합니다.
  • ExecutorService:
    • 작업 제출 및 결과 관리.
    • 스레드 종료 (shutdown(), shutdownNow()).
    • 작업 결과 반환 (Future).

Executor를 사용하는 이유

  1. 스레드 관리: 스레드 생성과 관리를 직접 처리하지 않아도 됩니다.
  2. 효율적인 자원 활용: 스레드 재사용 및 작업 큐를 통해 효율적인 작업 처리.
  3. 다양한 실행 정책: 단일 스레드, 스레드 풀, 스케줄링 등 다양한 방식으로 작업 처리 가능.

위의 예제 코드는 다양한 상황에서 Executor를 활용하는 방법을 보여줍니다. Executor를 잘 활용하면 멀티스레드 프로그래밍의 복잡성을 크게 줄일 수 있습니다.

'Java' 카테고리의 다른 글

JMS(Java Message Service)  (0) 2024.11.07
Stream  (0) 2024.11.05
jar, war 설명과 차이  (0) 2024.10.09
Shallow copy와 Deep copy  (0) 2024.09.19
어그리게이션(Aggregation)과 컴포지션(Composition)  (0) 2024.08.21

+ Recent posts