Java/Thread

[Java] 멀티 스레드(Multi Thread) (6) : 스레드풀의 작업의 생성과 처리

아, 그래요? 2021. 12. 29. 16:51
작업 생성

각 작업은 Runnalbe 혹은 Callble 구현 클래스로 표현된다. Runnable과 Callable의 차이점은 리턴값의 유무이다. 다음은 Runnable과 Callable 구현 클래스의 작성 예시이다.

Runnable task = new Runnable() {
	@Override
    public void run() {
    	// ...
    }
}
Callable<T> callable = new Callable<T>() {
	@Override
    public T call() thorws Exception {
    	// ...
        return T;
    }
}

callable 구현객체는 리턴타입이 있어야 하며 리턴타입을 제네릭으로 선언한다. 그리고 runnable과 callalbe 구현 클래스는 각각 run(), call() 메서드를 오버라이딩하여 코드를 실행한다.

 

작업 처리 요청

위에서 말한 작업 생성은 말 그대로 객체를 생성하는 일이지 그 외에 어떠한 것도 아니다. 작업을 생성했다면 이제 처리를 요청해야 한다. 5편에서 다뤘지만 처리가 요청이 된 작업은 작업 큐에 삽입되게 된다. 이때의 작업 큐는 ExecutorService에 의해 구현된 객체가 가지고 있다.

 

작업 처리를 요청하는 메서드는 execute()와 submit()이 있다. 두 메서드의 차이는 다음과 같다.

execute() submit()
- Runnable을 작업 큐에 저장
- 작업 처리의 결과를 리턴하지 않음
- Runnable/Callable을 작업큐에 저장
- Future 객체로 작업 처리 결과를 리턴
public class ProcessingRequestExample {
	public static void main(String[] args) {
    	// 스레드를 최대 3개 가질 수 있는 스레드 풀 생성
    	ExecutorService executorService = new Executors.newFixedThreadPool(3);
        
        Runnable runnable = new Runnable() {
        	@Override
            public void run() {
            	// 실행코드
            }
        }
        executorService.execute(runnable);
        executorService.submit(runnable);
    }
}

 

execute() 메서드의 예외처리 방식으로 인한 스레드 생성 오버헤드

위에서 언급한 처리할 수 있는 구현객체의 종류, 처리의 결과 리턴 유무외에도 execute와 submit 메서드 사이에는 아주 큰 차이가 있다. 바로 예외처리 방식이다. execute() 메서드의 경우 작업 처리 중 예외가 발생 시 실행을 종료하고, 바로 스레드를 종료하고 스레드 풀을 빠져나간다. 그러면 새로운 스레드가 생성되게 된다. 이에 비해 submit()메서드의 경우 예외가 처리돼도 스레드는 종료되지 않은 다른 작업을 위해 재사용된다.

이로 인해 execute()의 경우 스레드 생성 오버헤드가 발생할 수 있다. (너무 많은 스레드 생성을 야기) 즉, 특별한 문제가 없다면 submit()을 작업처리를 위해 사용하는 것이 바람직하다. 

각각 실행코드에서 DivisionByZero 에러를 발생시켰다. (왼쪽은 execute(), 오른쪽은 submit())

위 그림은 각각 divisionByZero 에러를 발생시킨 runnblae객체 10개를 execute, submit으로 처리 요청을 하여 실행한 결과 이다. 먼저 execute로 실행한 경우를 보면 총 스레드의 개수는 3으로 유지되지만 작업 스레드가 계속 바뀌는 것을 볼 수 있다. 즉, 기존의 스레드가 제거되고 새로운 스레드가 계속해서 생성되는 것이다. 이는 스레드 생성 오버헤드를 발생시켜 시스템의 성능을 저하시킨다.

 

반면 submit 으로 작업 처리를 요청한 경우 스레드풀은 예외가 발생한 작업스레드를 재사용하기 때문에 작업스레드가 1,2,3만 사용되는 것을 볼 수 있다.