Notice
Recent Posts
Recent Comments
Link
Love Every Moment
〔Java〕쓰레드 풀(Thread Pool) 본문
반응형
1. 풀(Pool)
- 이미 사용할 준비가 된 자원을 메모리 위에 일정량 미리 생성해둔 자원의 집합
- 자원이 필요한 경우 새로 자원을 생성하는 대신 풀에서 꺼내어 사용
- 자원 사용을 완료한 경우 자원을 해제하는 대신 풀에 다시 반환
자원의 생성과 파괴에 드는 비용, 즉 오버헤드(Overhead)를 줄여준다는 장점이 있다
2. 쓰레드 풀(Thread Pool)
- 미리 쓰레드들을 생성해두었다가 작업 요청이 들어올 때마다 미리 생성된 쓰레드로 작업을 처리
- 작업이 끝난 쓰레드는 종료되지 않고 다음 작업 요청을 기다린다
- 쓰레드들을 풀에 생성 → 작업들을 태스크 큐(Task Queue)에 추가 → 쓰레드 별로 작업을 할당하여 처리
3. 쓰레드 풀의 생성
java.util.concurrent 패키지의 Executors 클래스의 메소드를 이용하여 ExecutorService 객체 생성
(1) newCachedThreadPool()
ExecutorService threadPool = Executors.newCachedThreadPool();
- 작업 요청이 들어올 때마다 쓰레드를 생성
- 생성된 쓰레드가 60초동안 유휴 상태이면 제거됨
- 초기 쓰레드 수: 0개
- 코어 쓰레드 수: 0개
- 최대 쓰레드 수: Integer.MAX_VALUE
(2) newFixedThreadPool()
ExecutorService threadPool = Executors.newFixedThreadPool(100);
- 현재 존재하는 쓰레드 수보다 작업량이 많으면 쓰레드를 생성
- 한 번 생성된 쓰레드는 유휴 상태가 오래 지나도 제거되지 않음
- 초기 쓰레드 수: 0개
- 코어 쓰레드 수: 쓰레드풀 생성시 지정
- 최대 쓰레드 수: 쓰레드풀 생성시 지정
(3) ThreadPoolExecutor()
ExecutorService threadPool = new ThreadPoolExecutor(
3, // 코어 쓰레드 수
100, // 최대 쓰레드 수
60, // 최대 유휴 시간
TimeUnit.SECONDS, // 최대 유휴 시간 단위
new LinkedBlockingQueue<Runnable>() // 작업 큐
);
- 초기, 코어, 최대 쓰레드 수를 모두 마음대로 지정해서 쓰레드 풀을 생성하는 방법
- 위의 newCachedThreadPool() 과 newFixedThreadPool() 도 내부적으로는 ThreadPoolExecutor()를 이용하여 구현되어 있음
4. 쓰레드 풀의 종료
(1) shutdown()
threadPool.shutdown();
- 현재 쓰레드들이 처리하고 있는 작업과 작업 큐에 대기하고 있는 작업을 모두 끝마친 뒤에 쓰레드 풀을 종료
(2) shutdownNow()
List<Runnable> unprocessedTasks = threadPool.shutdownNow();
- 현재 작업 중인 쓰레드를 강제 종료
- 작업 큐 대기열에 남아있는 작업들은 List<Runnable> 로 반환
(3) awaitTermination()
boolean complete = threadPool.awaitTermination(60, TimeUnit.SECONDS);
- shutdown() 을 먼저 호출
- 지정한 timeout 안에 모든 작업이 완료되면 true 를 반환
- 완료되지 못하면 작업을 처리 중이던 쓰레드를 강제 종료하고 false 를 반환
5. 쓰레드 풀에 작업 처리 요청
(1) execute()
- Runnable 만 처리 가능
- 작업의 처리 결과를 반환하지 않음
- 쓰레드가 작업 처리 중에 예외가 발생하면, 쓰레드 풀에서 해당 쓰레드를 제거하고 새로운 쓰레드 생성
(2) submit()
- Runnable 과 Callable 모두 처리 가능
- 작업의 처리 결과를 Future 라는 인터페이스로 반환(→자바스크립트의 Promise 와 유사)
- 작업 처리 중에 예외가 발생하더라도 쓰레드를 제거하지 않고 다음 작업에 재사용
- 일반적으로 submit() 이 execute() 보다 오버헤드가 적으므로 권장됨
public class myCallable implements Callable {
@Override
public Integer call() {
int count = 0;
for (int i = 0; i < 10; i++) {
try {
count += 1;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return count;
}
}
Future<?> future = executorService.submit(new myCallable());
try {
Object result = future.get(); // (1) 10초 동안 blocking 되었다가 반환
System.out.println("10s"); // (2) 10초 후에 출력
System.out.println("result = " + result); // (3) result = 10
} catch (Exception e) {
e.printStackTrace();
}
참고
Introduction to Thread Pools in Java | Baeldung
반응형
'PROGRAMMING::LANGUAGE > Java' 카테고리의 다른 글
〔Java〕해시맵(HashMap)과 해시테이블(HashTable) (0) | 2023.07.31 |
---|
Comments