
앞선 아티클에서 살펴본 작업처리 요청과 관련된 자세한 내용을 더 살펴보겠습니다.
멀티 스레드(9) - 스레드 풀 3 : 작업 생성과 처리 요청 1
○ 작업 생성 하나의 작업은 Runnable 또는 Callable 구현 클래스로 표현하게 됩니다. 두 구현 클래스의 차이는 리턴 값 유무의 여부인데, 아래 예시를 살펴보겠습니다. Runnable 구현 클래스Callable
nozeroslope.tistory.com
작업 처리 요청은, ExecutorService의 작업 큐에 Runnable 또는 Callable 객체를 넣는 행위를 의미합니다. ExecutorService는 작업 처리 요청을 위해 당므 두 가지 종류의 메서드를 제공합니다.
리턴 타입 | 메서드 명(파라미터) | 설명 |
void | execute(Runnable command) | - Runnable을 작업 큐에 저장 - 작업 처리 결과를 받지 못함 생성 |
Future<?> Future<V> Future<V> |
submit(Runnable task) submit(Runnable task, V result) submit(Callable<V> task) |
- Runnable 또는 Callable을 작업 큐에 저장 - 리턴된 Future를 통해 작업 처리 결과를 얻을 수 있음 |
여기서 execute( )와 submit( ) 메서드의 가장 큰 차이점은, execute( )는 작업 처리 결과를 받지 못하고 submit( )은 작업 처리 결과를 받을 수 있도록 Future를 리턴한다는 점 입니다.
또한 execute( )는 작업 중 예외가 발생하면 스레드를 중단하고 해당 스레드는 스레드풀에서 제거됩니다. 그래서 스레드풀은 다른 작업 처리를 위해서 새로운 스레드를 생성하게 됩니다. 반면 submit( )은 작ㅇ버 처리 도중 예외가 발생하더라도 스레드는 종료되지 않고 다음 작업을 위해 재사용됩니다.
위와 같은 이유로, 가급적이면 스레드의 오버헤더를 줄이기 위해서 submit( ) 사용이 권장됩니다.
아래 예제에서는 Runnable 작업 정의 시, Integer.parseInt("삼")을 넣어서 NumberFormatException을 유도합니다. 10개의 작업을 execute( )와 submit( ) 메서드로 각각 처리 요청 했을 때, 스레드풀의 상태를 보도록 하겠습니다.
public class ExampleMain {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
for(int i=0; i<10; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
// 스레드 총 개수 및 작업 스레드 이름 출력
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
int poolSize = threadPoolExecutor.getPoolSize();
String threadName = Thread.currentThread().getName();
System.out.println("[총 스레드 개수: " + poolSize + "] 작업 스레드 이름: " + threadName);
// 예외 발생 시킴
int value = Integer.parseInt("삼");
}
};
// 작업 처리 요청
executorService.execute(runnable);
// executorService.submit(runnable);
// 콘솔에 출력 시간을 주기 위해서 0.01초 일시 정지
Thread.sleep(10);
}
executorService.isShutdown();
}
}
/* 출력
[총 스레드 개수: 1] 작업 스레드 이름: pool-1-thread-1
Exception in thread "pool-1-thread-1" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-3
Exception in thread "pool-1-thread-3" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-2
Exception in thread "pool-1-thread-2" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-4
Exception in thread "pool-1-thread-4" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-5
Exception in thread "pool-1-thread-5" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-6
Exception in thread "pool-1-thread-6" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-7
Exception in thread "pool-1-thread-7" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-8
Exception in thread "pool-1-thread-8" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-9
Exception in thread "pool-1-thread-9" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-10
Exception in thread "pool-1-thread-10" java.lang.NumberFormatException: For input string: "삼"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at chap06/chap06.class00.ExampleMain$1.run(ExampleMain.java:25)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
*/
위와 같이 runnable을 execute로 실행했을 경우 최대 스레드는 2개로 변함이 없지만, 실행 스레드의 이름을 보면 모두 다른 스레드가 작업을 처리합니다. 작업 처리 도중 예외가 발생해서, 해당 스레드가 제거되고 새 스레드가 계속 생성되었기 때문입니다.
이번에는 executorService.submit(runnable); 의 주석을 제거하고 execute 라인에 주석을 추가해서 실행해 보겠습니다.
/* 출력
[총 스레드 개수: 1] 작업 스레드 이름: pool-1-thread-1
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-2
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-1
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-2
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-1
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-2
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-1
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-2
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-1
[총 스레드 개수: 2] 작업 스레드 이름: pool-1-thread-2
*/
예외가 발생하더라도 스레드가 종료되지 않고 계속 자사용되며 다른 작업을 처리하고 있는 것을 확인 가능합니다.
'Programming > JAVA' 카테고리의 다른 글
멀티 스레드(9) - 스레드 풀 4 : 블로킹 방식의 작업 완료 통보 1 (0) | 2025.01.15 |
---|---|
멀티 스레드(9) - 스레드 풀 3 : 작업 생성과 처리 요청 1 (0) | 2025.01.12 |
멀티 스레드(9) - 스레드 풀 2 : 스레드 풀 생성 및 종료 3 (0) | 2025.01.10 |
멀티 스레드(9) - 스레드 풀 2 : 스레드 풀 생성 및 종료 2 (0) | 2025.01.08 |
멀티 스레드(9) - 스레드 풀 2 : 스레드 풀 생성 및 종료 1 (2) | 2025.01.07 |