본문 바로가기

Java

모던 자바 인 액션 - Executor와 쓰레드 풀

Java - executor 포스팅에서는 Java API 문서를 보면서 Executor, 스레드 풀, 테스크에 대한 정리를 해보았는데요. 조금 내용이 부족한 것 같아. 모던 자바 인 액션에 나와있는 내용을 추가로 정리해보도록 하겠습니다. 

 

스레드의 문제


Java 스레드는 직접 운영체제 스레드에 접근합니다. 운영체제 스레드를 만들고 종료하려면 비싼 비용을 지불해야 합니다. 더욱이 운영체제 스레드의 숫자는 제한되어 있는 것이 문제입니다.

 

운영체제가 지원하는 스레드 수를 초과해 사용하면 자바 애플리케이션이 예상치 못한 방식으로 크래시될 수 있으므로 기존 스레드가 실행되는 상태에서 계속 새로운 스레드를 만드는 상황이 일어나지 않도록 주의해야 한다고 합니다.

 

그리고 최적의 자바 스레드 개수는 하드웨어 코어의 개수에 따라 달라지지만 스레드를 직접 생성할 경우, 이를 관리하기가 어렵다고 합니다.

 

스레드 풀의 장점


스레드 풀은 스레드를 모와놓은 공간을 의미하는데 태스크가 들어오면 스레드 풀에서 유휴중인 스레드를 통해 태스크를 제출된 순서대로 실행한다. 

 

하드웨어에 맞는 수의 태스크를 유지가 가능하다고 합니다. 아마도 스레드를 고정할 수 있기 때문에 Queue에 들어가는 태스크도 일정 수를 유지할 수 있다고 하는 것이 아닌가 싶습니다.

 

두번째로 수 천개의 태스크를 스레드 풀에 아무 오버헤드 없이 제출할 수 있다고 합니다. 아마도 스레드 생성, 종료 등을 하지 않아도 되니까 그런 것 같네요.

 

마지막으로 큐 크기 조정, 거부 정책, 태스크 종류에 따른 우선순위 등 다양한 설정을 제공한다고 합니다.

 

 

스레드 풀의 단점


책에서는 스레드 풀을 사용하는 것이 일반적으로 더 낫다고 말합니다. 하지만 2가지를 주의해야 한다고 조언해주는데요.

 

첫 째, K개의 스레드를 가진 스레듣 풀은 오직 K만큼의 스레드를 동시에 실행할 수 있다. 초과로 제출된 태스크는 큐에 저장되며 이전 태스크 중 하나가 종료되기 전까지는 스레드에 할당하지 않는다.

 

스레드가 잠을 자거나 I/O를 기다리는 블록 상황이 있드면 이 문제에 대해 주의해야 한다고 말한다. 잠을 자거나 I/O를 기다리는 상태에서는 워커 스레드에 할당된 상태를 유지하지만 아무 작업도 하지 않게 되기 때문이다.

 

둘째, 프로그램을 종료하기 전에 모든 스레드 풀을 종료해야 한다. 풀의 워커 스레드가 만들어진 다음 다른 태스크 제출을 기다리면서 종료되지 않은 상태일 수도 있기 때문이다.