스레드 풀(Thread Pool)은 미리 생성된 일정 수의 스레드 묶음으로, 여러 작업을 동시에 효율적으로 처리하기 위해 사용됩니다. 매번 새로운 스레드를 생성하지 않고 재사용 가능한 스레드를 미리 준비해두는 방식으로, 시스템 자원 소모를 줄이고 작업 처리 성능을 향상시킵니다.
스레드 풀의 작동 방식
- 스레드 생성: 애플리케이션이 시작될 때, 설정된 수만큼의 스레드를 미리 생성합니다. 이 스레드들은 작업이 할당되기를 기다리면서 풀 안에 대기 상태로 있습니다.
- 작업 할당: 작업이 요청되면, 스레드 풀에서 대기 중인 스레드가 할당되어 해당 작업을 처리합니다.
- 스레드 반환: 작업이 끝나면, 해당 스레드는 종료되지 않고 다시 풀로 반환되어 다음 작업을 처리할 준비를 합니다. 이로써 스레드를 지속적으로 재사용할 수 있습니다.
- 대기열 관리: 최대 스레드 수를 초과하는 작업이 들어오면, 해당 작업은 대기열에 추가되어 빈 스레드가 사용 가능할 때까지 대기합니다.
스레드 풀의 장점
- 자원 효율성: 미리 생성된 스레드를 재사용하여 스레드 생성과 종료로 인한 시스템 자원 낭비를 줄입니다.
- 성능 향상: 요청이 들어올 때마다 새로 스레드를 생성하는 것보다, 이미 준비된 스레드를 사용하는 것이 성능상 훨씬 유리합니다.
- 안정성: 스레드 풀을 사용하면 동시에 수행할 수 있는 작업 수를 제한할 수 있어, 과도한 스레드 생성으로 인한 시스템 과부하를 방지할 수 있습니다.
- 응답 시간 단축: 스레드가 미리 준비되어 있으므로, 작업이 요청되면 즉시 스레드를 할당할 수 있어 빠르게 응답할 수 있습니다.
Java에서 스레드 풀 생성 방법
Java에서는 ExecutorService
인터페이스와 Executors
클래스에서 제공하는 여러 스레드 풀 구현을 사용할 수 있습니다. 주로 다음과 같은 스레드 풀을 생성할 수 있습니다.
- Fixed Thread Pool: 고정된 크기의 스레드 풀을 생성합니다. 일정 수의 스레드를 미리 생성해두고 재사용합니다.
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
- Cached Thread Pool: 필요에 따라 새로운 스레드를 생성하고, 일정 시간 동안 사용되지 않은 스레드는 제거합니다. 짧은 시간에 많은 작업이 들어올 때 유용합니다.
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
- Single Thread Executor: 하나의 스레드만 사용하는 스레드 풀로, 하나의 작업만 순차적으로 처리합니다. 작업을 순서대로 처리할 때 유용합니다.
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
- Scheduled Thread Pool: 일정 시간 간격으로 작업을 실행하거나, 지연 작업을 스케줄링할 수 있는 스레드 풀입니다.
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
스레드 풀 예제 코드 (Fixed Thread Pool)
다음 예제는 고정 크기의 스레드 풀을 생성하고, 여러 작업을 스레드 풀에 제출하여 병렬로 실행하는 예입니다.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 3개의 스레드를 가진 고정 크기의 스레드 풀 생성
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 10개의 작업을 스레드 풀에 제출
for (int i = 0; i < 10; i++) {
int taskNumber = i;
executorService.submit(() -> {
System.out.println("Task " + taskNumber + " is running by " + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 작업 처리 시간 시뮬레이션
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskNumber + " is completed by " + Thread.currentThread().getName());
});
}
// 스레드 풀 종료
executorService.shutdown();
}
}
코드 설명
- 스레드 풀 생성:
Executors.newFixedThreadPool(3)
을 사용해 3개의 스레드를 가진 스레드 풀을 생성합니다. - 작업 제출:
executorService.submit()
메서드를 통해 작업을 제출하면, 3개의 스레드가 번갈아 가며 10개의 작업을 수행합니다. - 스레드 풀 종료:
shutdown()
메서드를 호출하여 스레드 풀의 작동을 중지합니다.
실행 예시
각 작업이 1초 동안 실행되며, 총 10개의 작업이 3개의 스레드에 할당되어 병렬로 처리됩니다. 스레드 풀을 사용하면 동시에 3개의 작업이 병렬로 수행됩니다.
요약
- 스레드 풀은 미리 생성된 스레드를 재사용하여, 시스템의 자원 효율성과 성능을 높이는 동시에 안정성을 제공하는 방식입니다.
- Java에서는
ExecutorService
와Executors
클래스를 통해 다양한 유형의 스레드 풀을 손쉽게 생성할 수 있습니다. - 스레드 풀은 특정 작업을 병렬로 효율적으로 처리하고 싶을 때 매우 유용하며, 특히 웹 서버나 대용량 데이터 처리 애플리케이션에서 자주 사용됩니다.
Apache Tomcat 서버에서 HTTP 요청을 처리할 때 스레드를 생성하고 관리하는 주체는 "톰캣의 스레드 풀"입니다. 톰캣은 특정 요청이 들어올 때마다 이를 처리할 수 있도록 스레드 풀(Thread Pool)을 사용해 스레드를 생성하거나 할당하여 요청을 처리합니다.
톰캣의 스레드 생성 및 관리 과정
- 스레드 풀 초기화: 톰캣이 시작될 때, 미리 지정된 수만큼의 스레드를 가진 스레드 풀이 초기화됩니다. 톰캣 설정 파일(
server.xml
)에서 이 스레드 풀의 초기 크기, 최대 크기, 타임아웃 등을 설정할 수 있습니다. - 요청 수신 및 스레드 할당: 클라이언트가 HTTP 요청을 보낼 때마다, 톰캣은 스레드 풀에서 빈 스레드를 할당하여 해당 요청을 처리합니다.
- 요청이 들어오면 스레드 풀에 미리 생성된 스레드가 요청을 처리하게 됩니다.
- 요청이 많아 기존 스레드가 부족한 경우, 스레드 풀이 설정된 최대치까지 스레드를 추가 생성합니다.
- 요청 처리 완료 후 스레드 반환: 요청 처리가 완료되면 해당 스레드는 다시 스레드 풀로 반환되어 다음 요청을 처리할 준비를 합니다. 이로써 스레드 재사용이 가능해지고, 서버 성능이 최적화됩니다.
- 최대 스레드 수 초과 시 큐 대기: 최대 스레드 수를 초과하는 요청이 들어오면, 해당 요청은 큐에서 대기합니다. 대기하는 동안 스레드가 사용 가능해지면 요청을 처리합니다.
톰캣의 스레드 풀 설정 (server.xml)
톰캣의 server.xml
파일에서 커넥터 설정을 통해 스레드 풀 관련 설정을 할 수 있습니다. 다음은 기본적인 스레드 풀 설정 예입니다.
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="10"
acceptCount="100"
redirectPort="8443" />
- maxThreads: 최대 스레드 수로, 동시 요청을 처리할 수 있는 최대 스레드 개수를 의미합니다.
- minSpareThreads: 톰캣이 유지하는 최소 스레드 수로, 초기화 시 최소한으로 준비할 스레드 수를 설정합니다.
- acceptCount: 최대 스레드 수를 초과하는 요청이 들어올 때 대기할 수 있는 큐의 크기입니다.
요약
- 톰캣 스레드 풀이 HTTP 요청을 처리하기 위해 스레드를 생성하고 관리합니다.
- 톰캣은 최소/최대 스레드 수를 설정하여 스레드를 생성, 반환하면서 요청을 처리하고, 필요 시 최대치까지 스레드를 추가 생성합니다.
- 스레드 풀을 사용하면 요청마다 새 스레드를 생성하는 것보다 성능과 자원 관리 측면에서 효율적입니다.
'Springboot Study > Springboot Security' 카테고리의 다른 글
Filter (FilterChain) (0) | 2024.10.31 |
---|---|
Spring Security에서 중요한 인터페이스들 (0) | 2024.10.30 |
세션(Session)과 제이슨웹토큰(JSON Web Token) (0) | 2024.10.29 |
OAuth (1) | 2024.10.28 |
인증(Authentication)과 권한 부여(Authorization) (0) | 2024.10.28 |