Java의 ThreadPoolExecutor를 활용하여 Singleton 패턴 기반의 커스텀 스레드 풀을 구현하고, 여러 개의 작업을 스레드 풀에서 실행하는 예제입니다.
CustomThreadPool 클래스는 Java의 ThreadPoolExecutor를 활용하여 최소/최대 스레드 개수, 대기 큐 크기 및 스레드 유지 시간을 설정한 후, 단일 인스턴스로 관리하는 Singleton 패턴을 적용한 스레드 풀입니다.
● 실행 흐름 :
- 최대 2개의 스레드가 즉시 실행됩니다.
- 이후 최대 5개의 작업이 대기 큐에 쌓입니다.
- 대기 큐가 가득 차면 새로운 스레드를 생성하여 실행합니다. (최대 10개)
- 10개의 작업이 순차적으로 실행된 후 스레드 풀이 종료됩니다.
import java.util.concurrent.*;
public enum CustomThreadPool {
INSTANCE;
private static final int CORE_POOL_SIZE = 2; // 최소 스레드 개수
private static final int MAX_POOL_SIZE = 10; // 최대 스레드 개수
private static final int QUEUE_CAPACITY = 5; // 대기 큐 크기
private static final long KEEP_ALIVE_TIME = 60L; // 유휴 스레드 유지 시간 (초)
private final ThreadPoolExecutor executor;
// enum에서 생성자를 사용하여 인스턴스를 초기화
CustomThreadPool() {
this.executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.AbortPolicy() // 큐가 가득 차면 예외 발생
);
}
// Singleton 인스턴스를 가져오는 방법: enum을 통해 인스턴스를 직접 접근
public static CustomThreadPool getInstance() {
return INSTANCE;
}
// 작업 실행 메서드
public void executeTask(Runnable task) {
executor.execute(task);
System.out.println("Active Threads: " + executor.getActiveCount() +
", Queue Size: " + executor.getQueue().size());
}
// 안전한 종료
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
public class MainApp {
public static void main(String[] args) {
CustomThreadPool pool = CustomThreadPool.getInstance();
for (int i = 1; i <= 10; i++) {
final int taskNumber = i;
pool.executeTask(() -> {
System.out.println(Thread.currentThread().getName() + " - Task " + taskNumber);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
pool.shutdown(); // 모든 작업이 끝나면 스레드 풀 종료
}
}
● 출력결과 :
pool-1-thread-1 - Task 1
pool-1-thread-2 - Task 2
Active Threads: 2, Queue Size: 5
Active Threads: 2, Queue Size: 5
...
pool-1-thread-3 - Task 3
pool-1-thread-4 - Task 4
...
pool-1-thread-10 - Task 10
● 핵심정의 :
- Singleton 패턴 적용
- ThreadPoolExecutor 활용 (최소/최대 스레드 개수, 대기 큐 설정)
- 안전한 종료 메커니즘 제공
- 다중 작업을 효율적으로 처리 가능
이러한 커스텀 스레드 풀은 대량의 작업을 병렬 처리하는 서버 애플리케이션, 백그라운드 작업, 데이터 처리 시스템 등에 활용될 수 있습니다.
● 단순히 고정된 스레드 풀을 사용하려는 목적 :
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
for (int i = 1; i <= 5; i++) {
final int taskNumber = i;
pool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " - Task " + taskNumber);
try {
Thread.sleep(1000); // 작업이 1초 걸린다고 가정
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
pool.shutdown();
}
● 출력결과 :
pool-1-thread-1 - Task 1
pool-1-thread-2 - Task 2
pool-1-thread-2 - Task 3
pool-1-thread-1 - Task 4
pool-1-thread-1 - Task 5
단순히 고정된 스레드 풀을 사용하려는 목적이라면 ExecutorService pool = Executors.newFixedThreadPool(5); 방식이 훨씬 간단하고 효율적입니다.
- 간결한 코드 : 스레드 풀을 사용하는 데 필요한 설정이 매우 직관적이고 간단합니다. 풀의 크기만 지정하면 되므로 복잡한 설정 없이 바로 사용할 수 있습니다.
- 자동 관리 : Executors.newFixedThreadPool()을 사용하면 스레드 풀의 크기와 관리를 자동으로 처리해줍니다. 즉, 풀에 들어갈 스레드를 자동으로 생성하고, 작업 큐를 관리하며, 스레드의 유휴 시간과 종료 등을 관리합니다.
- 효율성 : 기본적으로 필요한 스레드 수만큼만 스레드가 생성되므로 불필요한 스레드를 생성하지 않고, 시스템 자원을 효율적으로 사용할 수 있습니다.
- 스레드 관리에 대한 신경을 덜어줌 : ExecutorService는 스레드 풀의 관리 및 스케줄링을 자동으로 처리해주기 때문에 개발자가 스레드 관리에 대해 신경 쓸 필요가 없습니다. 단순히 작업을 제출하면 풀에서 처리해줍니다.
'Java' 카테고리의 다른 글
| Java Singleton (2) | 2025.03.01 |
|---|---|
| Java 스레드 실행 및 안전한 종료 방법 (2) | 2025.02.16 |
| JAVA Index 기반 문자열 변형 및 랜덤 셔플러 (2) | 2025.02.15 |
| 비트 연산 (2) | 2025.01.31 |
| Java 빌더 패턴 (Builder Pattern) (0) | 2025.01.29 |
