기본 개념
- 프로세스
- 실행중인 프로그램, 메모리에 적재되어 있음, 메모리 공유X
- 쓰레드 (Thread)
- 프로세스 내에서 실행되는 단위이며, CPU의 실행단위
- 같은 프로세스내에서 메모리 공간을 공유하며 작업을 병렬로 수행가능
- 쓰레드 풀이란
- 동시에 실행되는 작업(쓰레드)를 관리하는 데 사용되는 기법
- 현재 풀이 corePoolSize보다 많은 수의 스레드들을 가지고 있다면 초과된 스레들은 keep-alive Time시간보다 더 오래 할 일이 없다면 제거된다.
쓰레드 풀을 쓰는 이유 & 주의 할 점
- 원인 다중 스레드를 사용하는 경우, 특정 서비스가 실행될 때마다 스레드를 생성하는데 소요되는 시간이 문제가된다.
- 과정 그래서 프로세스를 시작할 때, 아예 일정한 수의 쓰레드들을 미리 풀로 만들어 두는 것이다.
- 결과 새 스레드를 매번 만들기보다, 기존의 스레드를 재사용하는 것이 종종 더 빠르다
- 또한 Maximum 쓰레드 개수를 정해야한다. 안그러면 CPU 시간, 메모리 공간과 같은 시스템이 고갈이 된다.
- 많은 수의 병렬 처리가 불가능한 시스템에서 쓰레드 개수를 제한 할 수 있어서 도움이 된다.
쓰레드 풀 동작 방식
- 사용후 반납 시스템
- 풀에 사용 가능한 쓰레드가 있으면 사용하고, 사용가능한 쓰레드가 없으면 사용가능 한것이 생길 때 까지 작업이 대기 된다.
쓰레드 풀 종류
ThreadPoolExecutor 설정을 통해 직접 커스텀 가능
- Single Thread Executor
- 단일 작업 쓰레드를 이용한다.
- 작업들은 순차적으로 실행되는 것이 보장되며 한번에 하나의 작업만이 활성화된다.
- 실패 시 새로 쓰레드 생성하지 않음
- Fixed Thread Executor
- 고정된 수만큼의 쓰레드를 이용한다.
- 기본설정으로 작업을 무한으로 대기할 수 있는 LinkedBlockingQueue를 사용
- 재사용을 위해 쓰레드가 죽지 않고 계속 유지된다.
언제 사용할까
1. 작업 개수가 일정하고, 적절한 쓰레드 개수를 유지하고 싶을 때
2. CPU 또는 I/O 작업을 제한된 개수의 쓰레드로 효율적으로 실행하고 싶을 때
3. 작업이 많아도 쓰레드 개수를 제한해서 과부하를 방지하고 싶을 때
주의할점
1. 무한 대기 큐로 인해 메모리 초과 위험이 있을 경우 ⇒ 큐의 크기를 제한해야함
2. 작업량이 급변할 경우에는 처리속도가 느리다⇒ CachedThreadPool이 더 적절
3. Cached Thread Pool
- 필요할 때 마다 새로운 쓰레드를 생성하는 쓰레드 풀이다. 하지만 이전에 생성했던 쓰레드들이 사용이 가능하다면 재사용한다.
- 비동기 작업에 사용하기 좋음
- 설정한 기본 keep alive 시간(60초) 동안 쓰레드 재사용이 가능하다. 지나면 종료됨.
- 내부적으로 SynchronousQueue 를 사용해, 작업이 즉시 실행되어야한다. 만약 사용가능한 쓰레드가 없으면 새로운 쓰레드를 즉시 생성함.
- 작업량이 급증할때 빠르게 확장 가능하지만, 너무 많은 쓰레드가 생성될 위험이 있다.
언제 사용할까
1. 작업이 매우 짧고 빠르게 실행되는 경우
2. 작업량이 예측 불가능 할때
3. 작업이 즉시 실행되야할 때
주의할 점
너무 많은 쓰레드가 생성될 수 있어서 메모리 리소스를 초과할 수 있음 ⇒ 직접 ThreadPoolExecutor를 생성해서 쓰레드 최대 개수를 제한 할 수 있음
4. Scheduler Thread Pool
- 주어진 delay 후에 실행하거나 주기적으로 실행한다.
5. Work Stealing Thread Pool
- JAVA 8부터 새로 생김
- 쓰레드를 동적으로 늘리고 줄일 수 있음
- 요청된 병렬 동작을 지원할 만큼, 충분한 쓰레드를 유지하고, 쓰레드마다 독립적인 큐를 사용
- 따라서 작업 큐가 비어있는 쓰레드가 존재한다면, 다른 쓰레드의 작업 큐에서 작업을 훔칠 수 있음 (놀고 먹는 쓰레드 에게 다른 쓰레드의 일을 도울 수 있도록 설계?)
- 그래서 작업이 실행되는 순서를 보장하지 않음 ( 큐잉 순서와 무관하게 동작)
- Fork-Join 기법 과 연관성 높음
- Fork-Join에 기반해서,작업을 잘게 나누어 병렬 처리를 한 후에 join하여 합산하는 방식이다.
- 쓰레드를 만들고 제거하는 자체가 오버헤드가 크니, 작업을 잘게 나눠서 작업 큐에서 task를 꺼내서 병렬로 처리한다.
- 따라서 일정한 개수의 쓰레드를 유지하고, 쓰레드마다 독립적인 작업큐를 관리하여, 하나의 쓰레드 큐가 비게 되면 다른 쓰레드에서 task를 훔쳐올수 있게 한다면 효율적으로 동작할 수 있다.
Fixed Thread Executor에서의 쓰레드풀의 크기 설정
- CPU의 수, 물리 메모리 용량, 동시 요청 클라이언트 최대 개수등을 고려해서 정해진다.
- 시스템 부하가 적을 때는 작은 풀 크기로 바꾸어 메모리 소모를 줄일 수 있다.
- 스레드 풀 적정 크기 = cpu 코어 개수 * (1 / cpu 사용시간)
Fixed Thread Executor에서 오래 실행되는 쓰레드가 많을 경우 어떻게 관리할까
- 오래 실행되는 쓰레드가 많을수록 쓰레드 풀의 응답속도는 느려지게 된다.
- 따라서 계속 대기하는 기능 대신 일정시간 동안만 대기하는 메소드를 사용할 수 있다면 응답 속도를 향상 시킬 수 있다. ⇒ Blocking Queue 사용
- 집중 대응 정책
- 중단 정책 : execute 메소드에서 RejectedExecutionException을 던진다.
- 제거 정책 : 큐에 추가하려던 작업을 제거해버린다.
- 호출자 실행 정책 : 작업을 프로듀서에게 거꾸로 넘겨, 작업 속도를 늦출 수 있도록 일종의 속도 조절방법으로 사용된다.
- 메인 쓰레드가 해당 작업을 직접처리함으로써, 또 다른 새로운 작업이 추가되지 못하도록 한다.
- 따라서 그 시간 동안 쓰데르는 큐의 작업을 처리할 시간을 가지게 된다.
Blocking Queue
1. 쓰레드 안전하다
- 내부적으로 동기화되어 있어서 여러 스레드에서 동시에 접근해도 안전하다.
2. 대기하는데 시간제한을 할 수 있다.
- offer(E e, long timeout, TimeUnit unit) 및 poll(long timeout, TimeUnit unit)로 대기 시간을 설정할 수 있다. 지정된 시간 내에 연산이 완료되지 않으면 타임아웃과 함께 실패한다
Blocking Queue의 구현체
- ArrayBlockingQueue
- 고정 크기의 배열을 기반으로 한 구현.
- 크기가 일단 설정되면 변경할 수 없고, 구현 시 크기를 지정해 주어야 한다.
- 따라서 큐가 다 차게 되면 RejectedExecutionHandler가 데이터 처리를 못하게 되었을 때 어떻게 거절 처리할 것인지를 정의해야한다.
- [기본값] LinkedBlockingQueue
- 연결 노드를 기반으로 한 구현. 선택적으로 최대 크기를 설정할 수 있다. ( 큐 사이즈를 지정할 필요가 없으나, 지정하는 이유는 처음부터 해당 QueueSize만큼의 공간을 확보하기 위함이다.)
- 데이터를 무한정 넣을 수 있음 따라서 모든 요청에 대한 처리를 할 수 있는것이다. ⇒ 각각의 작업들이 다른 작업들에 대해 완전히 독립적일때 적당하다
- PriorityBlockingQueue
- 요소를 우선순위에 따라 저장하는 구현.
- SynchronousQueue
- 데이터 저장 없이 생산자(데이터 넣는 쓰레드)와 소비자(데이터를 꺼내는 쓰레드)가 즉시 만나야 하는 특별한 큐.
- 내부적으로 Transferer라는 객체를 사용하여 대기 중인 스레드를 관리한다.
- 공정하게 처리할 수도 있고, 성능을 위해 비공정 처리할 수도 있음.
공룡책 195쪽
[Thread Pool 적정 크기] https://medium.com/@10x.developer.kr/스레드-풀의-적절한-크기를-구하는-합리적인-방법-7af84b615623
[Thread Pool 위키피디아] https://en.wikipedia.org/wiki/Thread_pool
[Thread Pool 종류 구현체] https://blog.naver.com/xxrcn11/20170610296
[Blocking Queue, Delay Queue] https://olrlobt.tistory.com/66[Work Stealing] https://velog.io/@vies00/Java-work-stealing-fork-join-xljtjnflly
[Thread Pool 종류] https://velog.io/@haero_kim/Java-Thread-Pool-개념과-동작원리
[CachedThreadPool] https://stackoverflow.com/questions/17957382/fixedthreadpool-vs-cachedthreadpool-the-lesser-of-two-evils
[내용 요약을 위해] ChatGPT 4o 사용
'CS > CS' 카테고리의 다른 글
@Transactional 도대체 언제 쓰고 언제 안써야해? (0) | 2025.02.26 |
---|---|
로드밸런싱 알고리즘과 SPOF에 의한 DNS 로드밸런싱 (0) | 2025.02.11 |
[DB] 데이터베이스와 SQL (0) | 2022.09.19 |
댓글