본문 바로가기

개발/Java, Spring

비동기 처리 - ExecutorService

Executor란?

 쓰레드풀을 구현한 구현체. Executor를 선언하고 거기에 task를 등록하면 알아서 적절한 쓰레드를 사용해 작업을 처리한다.

(단위작업 - Job 또는 Task, 여기서는 Task로 통일. 참고)

Executor의 종류에는 여러 가지가 있지만 여기서는 ExecutorService에 대해서 알아본다.



선언

여기서 살펴볼 ExecutorService에서 사용할 쓰레드풀 종류는 3가지가 있다.


1
2
3
4
5
ExecutorService fixedExecService = Executors.newFixedThreadPool(2); //thread 2개
ExecutorService CachedExecService = Executors.newCacahedThreadPool();
ExecutorService SingleExecService = Executors.newSingleThreadExecutor();
cs


FixedThreadPool

파라미터로 넘겨준 값만큼 쓰레드를 만들어놓는다.

코어 수만큼의 쓰레드를 만들려면 다음과 같이 하면 된다.


1
2
3
ExecutorService executorService = Executors.newFixedThreadPool(
    Runtime.getRuntime().availableProcessors()
);
cs


CachedThreadPool

필요한 만큼 가변적으로 쓰레드를 생성한다.

만들어놓은 쓰레드가 다 사용중인데 새로운 task가 들어오면 새로운 쓰레드를 만들고, 쓰레드가 60초간 작업이 없으면 삭제한다.


SingleThreadExecutor

단순히 하나의 쓰레드로 작업할 때 사용한다.



종료

ExecutorService의 종료와 관련된 메소드는 3가지가 있다.


1
2
3
executorService.shutdown();
executorService.shutdownNow();
executorService.awaitTermination(10, TimeUnit.SECONDS);
cs

void shoutdown()

현재 처리하고 있는 작업과 작업 큐에 들어있는 모든 작업을 처리한 뒤에 스레드 풀을 종료시킨다.

List<Runnable> shutdownNow()

현재 처리하고 있는 쓰레드를 interrupt로 중지하고, 스레드 풀을 종료시킨다. return값은 이 때 미처리된 작업들의 리스트를 반환한다.

Boolean awaitTermination(long timeout, TimeUnit unit)

shutdown() 메소드를 우선 호출하고, 주어진 timeout 내에 작업을 모두 완료했으면 true, 그렇지 않으면 작업중인 쓰레드를 interrupt로 종료시키고 false를 반환한다.

등록

Executor에 등록할 수 있는 task의 형태는 Runnable과 Callable 두 가지가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Runnable runnableTask = new Runnable() {
    @Override
    public void run() {
        // Process
    }
}
 
Callable<T> callableTask = new Callable<T>() {
    @Override
    public T call() throws Exception {
        // Process
        return T;
    }
}
cs

이 때, Runnable과 Callable의 가장 큰 차이점은 return 값의 유무이다.

이러한 Task를 등록할 때는 크게 두 가지 메소드를 사용한다.


execute

void execute(Runnable task)

Runnable 타입의 task를 작업 큐에 저장한다.
task의 타입이 Runnable 이므로 작업의 결과를 받아오지 못한다.

execute로 실행하는 쓰레드에서 예외가 발생했을 경우, 해당 쓰레드가 종료되고 쓰레드 풀에서 제거된다.
그 후에 다른 작업 처리를 위한 새로운 쓰레드를 생성해 풀에 추가한다.

submit

Future<?> submit(Runnable task)

Future<V> submit(Runnable task, V result)

Future<V> submit(Callable<V> task)

Runnable 혹은 Callable 타입의 task를 작업 큐에 추가한다.
submit에서 예외가 발생해도 쓰레드는 종료되지 않는다.

submit으로 원하는 작업을 작업큐에 등록하면, 그 즉시 Future 객체를 돌려받는다. 
이 Future 객체에서 값을 바로 얻어서 사용할 수 있는 것은 아니고 작업이 끝났을 때 돌려 받을 수 있다.

Future<V>

Executor에 task를 등록하고 돌려받은 객체.
이 객체에서 작업의 결과를 얻어내기 위해서는 get을 사용한다.

V get()

작업이 완료될 때까지 blocking 되어있다가 V 타입의 결과를 return한다.

1
V get() throws InterruptedException, ExecutionException
cs

return 값이 없는 task의 경우 future.get()을 했을 때, 정상적으로 종료되었으면 null, 아니면 Exception이 발생한다.

V get(long timeout, TimeUnit unit)

timeout 안에 작업이 완료되면 V 타입의 결과를, 그렇지 않으면 TimeoutException이 발생한다.

1
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
cs

'개발 > Java, Spring' 카테고리의 다른 글

비동기처리 - Future의 종류  (0) 2019.04.19