스레드를 직접 생성해서 사용하면 다음과 같은 3가지 문제를 직면합니다
1. 스레드 생성시간 성능 문제
2. 스레드 관리 문제
3. Runnable 인터페이스의 불편함
스레드를 사용하려면 먼저 스레드를 생성해야합니다
하지만 스레드 생성 비용은 다음과 같은 이유로 무겁습니다
각 스레드마다 자신의 호출 스택을 가지고 있어야 하며, 이것은 스레드가 실행되는 동안 사용되는 메모리 공간입니다
따라서 스레드를 생성할 때 호출 스택을 위한 메모리를 할당해야합니다
스레드를 생성하는 작업은 운영체제 커널 수준에서 이루어지고 시스템 콜을 통해 처리됩니다
이것은 CPU와 메모리 리소스를 소모합니다
새로운 스레드가 생성되면 운영체제의 스케줄러가 이 스레드를 관리하고 실행순서를 조정해야합니다
이것은 운영체제 스케줄링 알고리즘에 따라 추가적인 오버헤드가 발생할 수 있습니다
참고로 스레드 하나는 보통 1MB 이상의 메모리를 사용합니다
즉, 스레드를 생서앟는 작업은 자바 객체 하나 생성하는 것에 비해 상대적으로 무거운 작업입니다
이런 문제를 해결하려면 생성한 스레드를 재사용하는 방법을 고려할 수 있습니다
이렇게 한다면 처음 생성할 때 제외하고는 생성을 위한 시간이 들지 않고
스레드가 빠르게 작업을 진행할 수 있습ㄴ디ㅏ
서버의 CPU와 메모리는 자원이 한정되어있기 때문에 스레드를 무한하게 만들 수 없습니다
따라서 이러한 문제를 해결하기 위해서는 시스템이 버틸 수 있는 최대 스레드 수까지만
스레드를 생성할 수 있도록 관리해야합니다
또한 앱을 종료할 때, 안전한 종료를 위해 실행중인 스레드가 남은 작업은 모두 수행한 다음
프로그램을 종료하거나 급하게 종료해야해서 인터럽트의 신호르 ㄹ주고 스레드를 종료하고 싶다고 할 때
이러한 스레드가 어디선가 관리해야합니다
일단 Runnable의 run()메소드는 반환값을 가지지 않아 스레드 실행 결과를 직접 받을 수 없습니다
또한 체크 예외를던질 수 없고 이에 대해 처리하는 로직을 구현하거나 별도 방법을 사용해야합니다
이러한 1번 2번 문제를 해결하기 위해서는 스레드를 생성하고 관리하는 스레드 풀이 필요합니다
스레드 풀을 사용하면 스레드를 재사용할 수 있어 재사용 시의 스레드 생성 시간을 절약할 수 있습니다
또한 스레드 풀에서 관리하며 필요한 만큼만 스레드를 만들 수 있고 관리할 수 있습니다
스레드 풀은 스레드가 처리할 작업이 없다면 WAITING 상태로 관리하고
작업 요청이 오면 RUNNABLE 상태로 변경하는 작업을 해야합니다
개념은 쉬워보이는데 막상 구현하다보면 매우 복잡하다는 것을 알 수 있습니다
이런 복잡한 과정을 해결해주는 것이 바로 Excutor 프레임워크입니다
Executor 프레임워크는 스레드 풀, 스레드 관리, Runnable의 문제점은 뿐만아니라
생산자 소비자 문제까지 해결해주는 자바 멀티스레드 도구입니다
이것을 사용하면 앞선 문제를 편리하게 해결할 수 있습니다!