자바에서 ExecutorExecutorService는 자바의 동시성(concurrency) 프로그래밍을 위한 핵심 인터페이스입니다. 이들은 작업 실행을 추상화하여 개발자가 스레드 관리의 복잡성으로부터 벗어날 수 있게 돕습니다. 아래에서 각각에 대해 자세히 설명하겠습니다.
 

 
 
 
 

Executor

Executor 인터페이스는 java.util.concurrent 패키지에 속해 있으며, 단일 추상 메소드 execute(Runnable command)를 가지고 있습니다. 이 메소드는 주어진 작업(Runnable 객체)을 실행하는 방법을 정의합니다. Executor를 구현하는 클래스는 이 execute 메소드를 통해 어떻게 그리고 언제 작업을 실행할지 결정합니다. 이 인터페이스는 작업의 실행을 간단하게 추상화하여, 실행 메커니즘(예: 스레드 사용 방법)을 사용자로부터 숨깁니다.

Executor executor = anExecutor;
executor.execute(new Runnable() {
    public void run() {
        // 작업 내용
    }
});

 
Executor 인터페이스는 개발자들이 해당 작업의 실행과 쓰레드의 사용 및 스케줄링 등으로부터 벗어날 수 있도록 도와준다. 단순히 전달받은 Runnable 작업을 사용하는 코드를 Executor로 구현하면 다음과 같다

@Test
void executorRun() {
    final Runnable runnable = () -> System.out.println("Thread: " + Thread.currentThread().getName());

    Executor executor = new RunExecutor();
    executor.execute(runnable);
}

static class RunExecutor implements Executor {

    @Override
    public void execute(final Runnable command) {
        command.run();
    }
}
출처: https://mangkyu.tistory.com/259 [MangKyu's Diary:티스토리]

 

ExecutorService

ExecutorService는 Executor를 확장한 더 복잡한 인터페이스로, 생명주기 관리(lifecycle management)와 작업 실행 결과를 추적할 수 있는 기능을 제공합니다. ExecutorService를 사용하면, 비동기 작업을 제출하고, 작업이 완료될 때까지 기다리며, 작업 실행을 취소하고, 실행자 서비스를 종료할 수 있습니다. ExecutorService에는 작업을 제출하기 위한 다양한 submit 메소드가 있으며, 이들은 Future 객체를 반환하여 나중에 작업의 결과를 검색할 수 있게 합니다.

ExecutorService는 주로 다음과 같은 메소드들을 제공합니다:

  • shutdown(): 실행자 서비스를 순차적으로 종료시키며, 이미 제출된 작업은 실행되지만 새 작업은 받지 않습니다.
  • shutdownNow(): 실행자 서비스를 즉시 종료시키며, 대기 중인 작업은 실행되지 않습니다.
  • submit(Callable<T> task): 값을 반환할 수 있는 작업을 제출하고, 작업이 완료될 때 결과를 받을 수 있는 Future<T>를 반환합니다.
  • invokeAll(...): 작업 컬렉션을 실행하고, 모든 작업이 완료될 때까지 기다린 후, 결과를 반환합니다.

이미지 출처 :&nbsp; :&nbsp; https://mangkyu.tistory.com/259

 

ExecutorService 인터페이스에서 제공하는 주요 메소드들과 각각의 사용 예제를 아래에 설명하겠습니다. 이 인터페이스는 다양한 방법으로 작업을 실행하고, 관리하는 기능을 제공합니다

 

1. execute(Runnable command)

단순한 Runnable 작업을 실행합니다. 작업의 결과를 반환받을 수는 없습니다.

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
    public void run() {
        System.out.println("Asynchronous task");
    }
});
executorService.shutdown();

 

2. submit(Runnable task)

Runnable 작업을 실행하고, 작업이 완료될 때까지 기다리는 데 사용할 수 있는 Future<?>를 반환합니다.

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(new Runnable() {
    public void run() {
        System.out.println("Asynchronous task");
    }
});
executorService.shutdown();

 

3. submit(Callable<T> task)

Callable 작업을 실행하고, 작업의 결과를 받을 수 있는 Future<T>를 반환합니다.

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> future = executorService.submit(new Callable<String>() {
    public String call() {
        return "Result of the asynchronous computation";
    }
});
executorService.shutdown();

 

4. invokeAll(Collection<? extends Callable<T>> tasks)

주어진 작업들의 컬렉션을 실행하고, 모든 작업이 완료될 때까지 기다린 다음, 각 작업의 결과를 담은 List<Future<T>>를 반환합니다.

ExecutorService executorService = Executors.newSingleThreadExecutor();
List<Callable<String>> callables = Arrays.asList(
    () -> "Task 1",
    () -> "Task 2",
    () -> "Task 3"
);

try {
    List<Future<String>> futures = executorService.invokeAll(callables);
    for(Future<String> future : futures){
        System.out.println(future.get());
    }
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}
executorService.shutdown();

 

5. invokeAny(Collection<? extends Callable<T>> tasks)

주어진 작업들의 컬렉션 중 하나를 실행하고, 가장 먼저 완료되는 작업의 결과를 반환합니다. 나머지 작업은 취소됩니다.

ExecutorService executorService = Executors.newSingleThreadExecutor();
List<Callable<String>> callables = Arrays.asList(
    () -> {
        TimeUnit.SECONDS.sleep(2);
        return "Task 1";
    },
    () -> {
        TimeUnit.SECONDS.sleep(1);
        return "Task 2";
    },
    () -> {
        TimeUnit.SECONDS.sleep(3);
        return "Task 3";
    }
);

String result = executorService.invokeAny(callables);
System.out.println(result); // "Task 2" 의 결과가 가장 빨리 나올 것입니다.
executorService.shutdown();

 

ExecutorExecutorService는 자바에서 동시성을 다룰 때 중요한 구성 요소입니다. 이들을 사용함으로써 스레드를 직접 관리하는 복잡성을 줄이고, 효율적이고 안정적인 동시 실행을 구현할 수 있습니다.

 

6. shutdown()

실행자 서비스를 순차적으로 종료합니다. 이미 제출된 작업은 완료되지만, 새 작업은 받지 않습니다.

ExecutorService executorService = Executors.newSingleThreadExecutor();
// 작업 제출 등
executorService.shutdown();

 

7. shutdownNow()

실행자 서비스를 즉시 종료하고, 현재 대기 중이거나 실행 중인 작업 목록을 반환합니다.

ExecutorService executorService = Executors.newSingleThreadExecutor();
// 작업 제출 등
List<Runnable> notExecutedTasks = executorService.shutdownNow();

 

 

참고 : https://mangkyu.tistory.com/259

 

[Java] Callable, Future 및 Executors, Executor, ExecutorService, ScheduledExecutorService에 대한 이해 및 사용법

이번에는 자바5 부터 멀티 쓰레드 기반의 동시성 프로그래밍을 위해 추가된 Executor, ExecutorService, ScheduledExecutorService와 Callable, Future를 살펴보도록 하겠습니다. 1. Callable과 Future 인터페이스에 대한

mangkyu.tistory.com

 

+ Recent posts