개요
Java에서는 동시성 프로그래밍을 위해 Thread Class를 지원합니다.
이 Thread는 우리가 CS를 공부할 때 배웠던 Process, Thread의 Thread를 Java에서 구현한 것입니다.
Thread를 사용하면 Process보다 많은 자원을 절약할 수 있습니다.
하지만, Thread를 그냥 사용한다면 많은 오버헤드가 발생합니다.

Thread는 Kernel Thread, User Thread라는 두 종류가 있습니다.
JVM은 User Thread를 Kernel Thread하나와 매칭하여 동작시킵니다.
따라서, Java로 Thread객체를 만들 때 Kernel단에 갔다 와야 할 것입니다.
그렇게 되면, System call, Interrupt, ISR등의 과정을 거쳐야 하기 때문에 비용이 많이 발생합니다.
이런 문제점을 어떻게 해결할 수 있을까요?
Thread Pool
Thread Pool이라는 방법이 존재합니다.
Thread를 생성하고 지우는 데 자원이 많이 소모되므로, 일정 수의 Thread를 관리하는 방식입니다.
Thread Pool의 기본적인 구조는 아래와 같습니다.

그림에서는 Thread Pool에 5개의 Thread를 선제적으로 만들고, Application으로부터 Task를 받아와 Thread에 할당하는 모습을 볼 수 있습니다.
Thread를 미리 어느 정도 만들고 관리한다면, Thread생성과 제거에 대한 비용을 절감할 수 있을 것입니다.
1. Application에서 작업이 발생한다.
2. 발생한 작업을 Task Queue로 넘긴다.
3. ThreadPool에 Idle Thread가 있는지 검사한다.
4. Idle Thread에 Task Queue에서 작업을 가져와 처리한다.
ThreadPool은 이렇게 Thread를 새로 만들거나 제거하는 일을 최소로 하여 자원을 절약할 수 있습니다.
ThreadPool의 장점
ThreadPool은 Thread의 생성과 삭제에 대한 오버헤드를 줄일 수 있다는 데 그 장점이 있습니다.
ThreadPool이 없는 경우를 생각해보면, 그 해답이 될 것입니다.
사용자로부터 요청이 끝없이 들어옵니다. 그런데, 이 요청이 시스템의 처리량보다 큽니다.
작업이 끝나지 않았는데 새로운 스레드가 생성되고, 이러한 상황이 계속 반복됩니다.
이러한 상황이 계속 반복된다면, 시스템이 버티지 못할 수 있습니다.
1. Thread를 적정 수준 내로 관리한다면, Thread생성과 삭제에 대한 오버헤드가 최소로 줄어든다.
2. 과도한 작업에 대한 시스템 에러, 시스템 다운을 방지할 수 있다.
3. 다수의 작업을 안정적으로 처리할 수 있다.
이외에도 많은 장점이 있겠지만, 대표적으로 이러한 장점이 있을 것입니다.
ThreadPool의 단점
ThreadPool이 장점만 있는 것은 아닙니다.
ThreadPool 자체가 하나의 큰 자료구조이므로, 생성하는 데 비용이 발생할 것입니다.
또, ThreadPool에 지정한 스레드가 많다면 그것 또한 오버헤드일 것이고, 자원의 낭비를 초래할 수 있습니다.
Thread의 개수에 따라 최적화의 척도가 결정될 것입니다.
1. ThreadPool생성 시 Thread를 새로 만들고, 할당하고, Queue를 만들고... 자원이 필요하다.
2. Thread를 너무 많이 만든다면, 자원 낭비가 발생한다.
3. Thread를 너무 적게 만든다면, 요청을 효과적으로 처리하지 못한다.
4. 따라서, 시스템과 자료구조에 대한 이해가 어느 정도 필요하다.
ThreadPool은 효과적인 자료구조가 될 수 있지만, 사용자의 적절한 설정이 없다면 오히려 자원을 낭비하는 구조가 될 수 있습니다.
따라서 무엇보다 사용자가 시스템과 ThreadPool을 잘 이해하고 사용하는 것이 중요합니다.
ThreadPool 예시코드
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPoolTest {
public static void main(String[] args) {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
long threadpoolStart = System.currentTimeMillis();
long threadpoolEnd;
for (int i = 1; i <= 100000; i++) {
Runnable runnable = new ThreadPoolTime();
executor.execute(runnable);
}
while(true){
if(executor.getCompletedTaskCount() == 100000){
System.out.println("Completed : " + executor.getCompletedTaskCount());
threadpoolEnd = System.currentTimeMillis();
executor.shutdown();
break;
}
}
System.out.println("ThreadPool : " + (threadpoolEnd - threadpoolStart));
}
static class ThreadPoolTime implements Runnable{
@Override
public void run() {
int res = 0;
for(int i = 0; i < 100000; i++){
res++;
}
}
}
}
위의 코드를 통해 Java에서 ThreadPool을 사용해볼 수 있습니다.
newFixedThreadPool메서드를 통해 4개 Thread를 유지하는 ThreadPool을 받았습니다.
이후 Runnable들을 Task로 넣어, 10만 개의 작업을 완료하면 종료하고 ThreadPool을 없앴습니다.
ThreadPool을 shutdown으로 제거하지 않으면 프로그램이 종료되지 않을 수 있습니다.
'JAVA > 일반' 카테고리의 다른 글
[JAVA] JVM의 메모리구조 (0) | 2024.03.03 |
---|---|
JVM부터 JDK까지 (0) | 2023.12.18 |
개요
Java에서는 동시성 프로그래밍을 위해 Thread Class를 지원합니다.
이 Thread는 우리가 CS를 공부할 때 배웠던 Process, Thread의 Thread를 Java에서 구현한 것입니다.
Thread를 사용하면 Process보다 많은 자원을 절약할 수 있습니다.
하지만, Thread를 그냥 사용한다면 많은 오버헤드가 발생합니다.

Thread는 Kernel Thread, User Thread라는 두 종류가 있습니다.
JVM은 User Thread를 Kernel Thread하나와 매칭하여 동작시킵니다.
따라서, Java로 Thread객체를 만들 때 Kernel단에 갔다 와야 할 것입니다.
그렇게 되면, System call, Interrupt, ISR등의 과정을 거쳐야 하기 때문에 비용이 많이 발생합니다.
이런 문제점을 어떻게 해결할 수 있을까요?
Thread Pool
Thread Pool이라는 방법이 존재합니다.
Thread를 생성하고 지우는 데 자원이 많이 소모되므로, 일정 수의 Thread를 관리하는 방식입니다.
Thread Pool의 기본적인 구조는 아래와 같습니다.

그림에서는 Thread Pool에 5개의 Thread를 선제적으로 만들고, Application으로부터 Task를 받아와 Thread에 할당하는 모습을 볼 수 있습니다.
Thread를 미리 어느 정도 만들고 관리한다면, Thread생성과 제거에 대한 비용을 절감할 수 있을 것입니다.
1. Application에서 작업이 발생한다.
2. 발생한 작업을 Task Queue로 넘긴다.
3. ThreadPool에 Idle Thread가 있는지 검사한다.
4. Idle Thread에 Task Queue에서 작업을 가져와 처리한다.
ThreadPool은 이렇게 Thread를 새로 만들거나 제거하는 일을 최소로 하여 자원을 절약할 수 있습니다.
ThreadPool의 장점
ThreadPool은 Thread의 생성과 삭제에 대한 오버헤드를 줄일 수 있다는 데 그 장점이 있습니다.
ThreadPool이 없는 경우를 생각해보면, 그 해답이 될 것입니다.
사용자로부터 요청이 끝없이 들어옵니다. 그런데, 이 요청이 시스템의 처리량보다 큽니다.
작업이 끝나지 않았는데 새로운 스레드가 생성되고, 이러한 상황이 계속 반복됩니다.
이러한 상황이 계속 반복된다면, 시스템이 버티지 못할 수 있습니다.
1. Thread를 적정 수준 내로 관리한다면, Thread생성과 삭제에 대한 오버헤드가 최소로 줄어든다.
2. 과도한 작업에 대한 시스템 에러, 시스템 다운을 방지할 수 있다.
3. 다수의 작업을 안정적으로 처리할 수 있다.
이외에도 많은 장점이 있겠지만, 대표적으로 이러한 장점이 있을 것입니다.
ThreadPool의 단점
ThreadPool이 장점만 있는 것은 아닙니다.
ThreadPool 자체가 하나의 큰 자료구조이므로, 생성하는 데 비용이 발생할 것입니다.
또, ThreadPool에 지정한 스레드가 많다면 그것 또한 오버헤드일 것이고, 자원의 낭비를 초래할 수 있습니다.
Thread의 개수에 따라 최적화의 척도가 결정될 것입니다.
1. ThreadPool생성 시 Thread를 새로 만들고, 할당하고, Queue를 만들고... 자원이 필요하다.
2. Thread를 너무 많이 만든다면, 자원 낭비가 발생한다.
3. Thread를 너무 적게 만든다면, 요청을 효과적으로 처리하지 못한다.
4. 따라서, 시스템과 자료구조에 대한 이해가 어느 정도 필요하다.
ThreadPool은 효과적인 자료구조가 될 수 있지만, 사용자의 적절한 설정이 없다면 오히려 자원을 낭비하는 구조가 될 수 있습니다.
따라서 무엇보다 사용자가 시스템과 ThreadPool을 잘 이해하고 사용하는 것이 중요합니다.
ThreadPool 예시코드
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPoolTest {
public static void main(String[] args) {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
long threadpoolStart = System.currentTimeMillis();
long threadpoolEnd;
for (int i = 1; i <= 100000; i++) {
Runnable runnable = new ThreadPoolTime();
executor.execute(runnable);
}
while(true){
if(executor.getCompletedTaskCount() == 100000){
System.out.println("Completed : " + executor.getCompletedTaskCount());
threadpoolEnd = System.currentTimeMillis();
executor.shutdown();
break;
}
}
System.out.println("ThreadPool : " + (threadpoolEnd - threadpoolStart));
}
static class ThreadPoolTime implements Runnable{
@Override
public void run() {
int res = 0;
for(int i = 0; i < 100000; i++){
res++;
}
}
}
}
위의 코드를 통해 Java에서 ThreadPool을 사용해볼 수 있습니다.
newFixedThreadPool메서드를 통해 4개 Thread를 유지하는 ThreadPool을 받았습니다.
이후 Runnable들을 Task로 넣어, 10만 개의 작업을 완료하면 종료하고 ThreadPool을 없앴습니다.
ThreadPool을 shutdown으로 제거하지 않으면 프로그램이 종료되지 않을 수 있습니다.
'JAVA > 일반' 카테고리의 다른 글
[JAVA] JVM의 메모리구조 (0) | 2024.03.03 |
---|---|
JVM부터 JDK까지 (0) | 2023.12.18 |