1. Process
- 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당 받아 실행 중인 것을 의미한다.
- 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 스레드로 구성된다.
2. Thread
- Process 내에서 실제로 작업을 수행하는 주체를 의미한다.
- 모든 Process에는 한 개 이상의 Thread가 존재하여 작업을 수행한다.
- 하나의 프로세스를 구성하는 스레드들은 프로세스에 할당된 메모리, 자원 등을 공유한다.
- 프로세스와 같이 실행, 준비, 대기 등의 실행 상태를 가지며 실행 상태가 변할 때마다 Context Switching을 수행한다.
- 각 스레드 별로 자신만의 Stack과 Register를 가진다.
- 한 순간에 하나의 스레드만 실행 가능하다.
2.1 Process와 Thread 차이
- 프로세스는 운영체제로부터 자원을 할당 받는 작업의 단위이고, 스레드는 프로세스가 할당 받은 자원을 이용하는 실행의 단위이다.
구분 | 설명 |
Process | - 실행 중인 프로그램으로, 디스크로부터 메모리에 적재되어 CPU의 할당을 받을 수 있는 것을 의미한다. - 프로세스 생성은 많은 시간과 자원을 소비한다. |
Thread | - 프로세스의 실행 단위를 의미한다. - 한 프로세스 내에서 동작되는 여러 실행 흐름으로, 프로세스 내의 주소 공간이나 자원을 공유할 수 있다. - 각각의 스레드는 독립적인 작업을 수행하기 때문에 각자의 Stack과 PC Register 값을 갖고 있다. - 프로세스보다 생성 및 종료 시간, 스레드 간 전환 시간이 짧다. - 프로세스의 메모리, 자원 등을 고유하므로 커널의 도움 없이 상호 간에 통신이 가능하다. |
2.2 Stack을 Thread마다 독립적으로 할당하는 이유
- 스택은 함수 호출 시 전달되는 인자, 되돌아갈 주소값 및 함수 내에서 선언하는 변수 등을 저장하기 위해 사용하는 메모리 공간이다.
- 스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능하다는 것이고, 이는 독립적인 실행 흐름을 가능하게 할 수 있다는 것을 의미한다. 따라서 독립적인 실행 흐름을 위한 최소 조건으로 독립된 스택을 할당한다.
2.3 PC Register를 Thread마다 독립적으로 할당하는 이유
- PC(Program Counter) 값은 쓰레드가 명령어의 어디까지 수행하였는지를 나타낸다.
- 쓰레드는 CPU를 할당 받았다가 스케줄러에 의해 다시 선점 당한다. 이러한 이유로 명령어가 연속적으로 수행되지 못하기 때문에 어느 부분까지 수행했는지 기억할 필요가 있다. 따라서 PC Register를 독립적으로 할당한다.
2.4 Context Switching
- 현재까지의 작업 상태나 다음 작업에 필요한 각종 데이터를 저장하고 읽어오는 작업을 의미한다.
- 컴퓨터에서 동시에 처리할 수 있는 최대 작업 수는 CPU의 코어 수와 같다. 만약 CPU의 코어 수보다 더 많은 스레드가 실행되면, 각 코어가 정해진 시간 동안 여러 작업을 번갈아가며 수행하게 된다. 이때 각 스레드가 서로 교체될 때 스레드 간의 Context Switching이 발생한다.
- Context Switching에 걸리는 시간이 커지면 커질 수록 멀티 스레딩의 효율은 저하된다. 오히려 많은 양의 단순한 계산은 싱글 스레드로 동작하는 것이 효율적일 수도 있기 때문에, 많은 수의 스레드를 실행하는 것이 언제나 좋은 성능을 보이는 것은 아니다.
2.5 Multi Thread
- 일반적으로 하나의 프로세스는 하나의 스레드를 가지고 작업을 수행한다.
- 멀티 스레드는 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것을 의미한다.
- 멀티 프로세스는 여러 개의 CPU를 사용하여 여러 프로세스를 동시에 수행하는 것을 의미한다.
- 멀티 스레드와 멀티 프로세스 모두 여러 흐름을 동시에 수행한다는 공통점을 가지고 있지만, 멀티 프로세스는 각 프로세스가 독립적인 메모리를 가지고 별도로 실행되는 반면에 멀티 스레드는 각 스레드가 자신이 속한 프로세스의 메모리를 공유한다는 점이 다르다.
- 멀티 스레드는 각 스레드가 자신이 속한 프로세스의 메모리를 공유하므로 시스템 자원의 낭비가 적다. 또한 하나의 스레드가 작업을 할 때 다른 스레드가 별도의 작업을 할 수 있어 사용자와의 응답성도 좋아진다.
2.6 Thread Group
- 서로 관련이 있는 스레드를 하나의 그룹으로 묶어 다루기 위한 장치이다.
- 다른 스레드 그룹을 포함할 수도 있으며, 이렇게 포함된 스레드 그룹은 트리 형태로 연결된다. 이때 스레드는 자신이 포함된 스레드 그룹이나 그 하위 그룹에는 접근할 수 있지만, 다른 그룹에는 접근할 수 없다.
- 스레드가 접근할 수 있는 범위를 제한하는 보안상으로 중요한 역할을 한다.
2.7 Thread Pool
- 필요한 스레드를 스레드 풀에 보관하고 관리한다.
- 스레드 풀에 생성 가능한 스레드의 최대치를 관리한다.
- 스레드가 필요하면, 이미 생성되어 있는 스레드를 스레드 풀에서 꺼내서 사용한다. 사용을 종료하면 스레드 풀에 해당 스레드를 반납한다.
- 최대 스레드가 모두 사용중이어서 스레드 풀에 스레드가 없으면, 기다리는 요청을 거절하거나 특정 숫자만큼 대기하도록 설정할 수 있다.
- 요청 마다 스레드가 생성될 때 발생하는 단점을 보완한다. 스레드가 미리 생성되어 있으므로 스레드를 생성하고 종료하는 비용이 절약되고, 응답 시간이 빠르다.
- 생성 가능한 스레드의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청을 안전하게 처리할 수 있다.
2.7.1 Max Thread
- 멀티 스레드에 대한 부분은 WAS가 처리하기 때문에, 개발자가 멀티 스레드 관련 코드를 신경쓰지 않아도 된다. 싱글 스레드 프로그래밍을 하듯이 개발하되 싱글톤 객체만 주의해서 사용하면 된다. 대신 WAS의 주요 튜닝 포인트는 Max Thread 수이다.
상황 | 설명 |
Max Thread를 너무 낮게 설정했을 경우 | 동시 요청이 많을 경우, 서버 리소스는 여유롭지만 클라이언트는 금방 응답이 지연된다. |
Max Thread를 너무 높게 설정했을 경우 | 동시 요청이 많을 경우, CPU, 메모리 리소스 임계점 초과로 서버가 다운된다. |
2.8 Daemon Thread
- 다른 일반 스레드의 작업을 돕는 보조적인 역할을 하는 스레드를 의미한다.
- 일반 스레드가 모두 종료되면 더는 할 일이 없으므로, 데몬 스레드 역시 자동으로 종료된다.
- 생성 방법과 실행 방법은 모두 일반 스레드와 동일하다.
- 일정 시간마다 자동으로 수행되는 저장 및 화면 갱신 등에 이용된다.
2.8.1 Garbage Collector
- 데몬 스레드를 이용하는 가장 대표적인 예시이다.
- 프로그래머가 동적으로 할당한 메모리 중 더 이상 사용하지 않는 영역을 자동으로 찾아내 해제해 주는 데몬 스레드를 의미한다.
- Java에서는 프로그래머가 메모리에 직접 접근하지 못하게 하는 대신에 가비지 컬렉터가 자동으로 메모리를 관리한다.
- 가바지 컬렉터가 동작하는 동안에는 프로세스가 일시적으로 중지되므로 성능 저하가 발생한다.
참고
- http://tcpschool.com/java/java_thread_concept
- https://goodgid.github.io/What-is-Thread/
- https://tcpschool.com/java/java_thread_multi
- https://limkydev.tistory.com/55
- 『스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술』