커스텀 스레드 풀


ThreadPoolExecutor 설정


ThreadPoolExecutor에 의해 스레드의 생성과 종료뿐만 아니라 Task의 큐잉에도 사용되며 다음과 같은 생성자에서 수행된다.



 ThreadPoolExecutor executor = new ThreadPoolExecutor(

   int corePoolSize, //핵심풀크기

   int maximumPoolSie,  //최대풀크기

   long keepAliveTime,  //생존 유지시간

   TimeUnit unit,  //생존 유지 시간의 단위

   BlockingQueue workQueue; //태스크 큐 유형

);




핵심풀 크기

스레드 풀에 포함되는 스레드의 하한, 실제로 스레드풀은0개 스레드로부터

시작하지만, 핵심 풀 크기에 도달하면 스레드 개수는 하한 이하로 떨어지지않는다.

풀에서 작업자 스레드의 개수가 핵심 풀크기보다 적을때, 태스크가 큐에 추가되면, 작업을 기다리는 유휴스레드가 있는경우에도 새로운 스레드가 생성될 것이다. 일단 작업자 스레드의 개수가 핵심풀크기보다 같거나 많아지면,

큐가 가득찬경우 새로운 작업자 스레드가 생성된다. 즉 큐는 스레드 생성에 대한 우선권을 얻는다.



최대 풀 크기

동시에 실행할 수 있는 스레드의 최대개수.

최대 풀 크기에 도달한 후, 큐에 더해진 태스크는 태스크를 처리할  유휴 스레드가 사용가능해질 떄까지 큐에서 기다린다.



최대 유휴시간(생존 유지시간)

유휴 스레드는 처리하기 위해 들어오는 태스크를 준비하기 위해 활성 상태를 유지하지만, 생존시간이 설정된 경우 시스템은 비핵심 풀 스레드를 회수할 수 있다.

생존시간은 TimeUnit에 의해 설정된 시간 단위로 측정된다.



태스크 큐 유형

Task가 작업자 스레드에 의해 처리될 수 있을때까지 소비자에 의해 더지핸 Task를 보유하는 BlockingQueue의 구현.



- 스레드 풀 설계

스레드 풀은 동시에 백그라운드 Task를 실행해야 하는 스레드를 관리하는데 

도움을 주지만, 사용자는 여전히 제한된 자원 소비와 높은 처리량을 얻기 위해 현명하게

설정해야 한다. 기본적인 목표는 필요한 것보다 더 많은 메모리를 사용하지 않고

하드웨어에 의해 허용되는 가장높은 속도로 작업을 처리하는 스레드 풀을 생성하는 것이다.




크기나스레드풀의 최대크기를 정한다. 스레드의 최대 개수가 너무작으면

충분한 속도로 큐에서 태스크를 꺼내지않아 성능저하될수있따.


예를들어 모든 스레드가 긴 I/O연산을 실행하는 경우, I/O 동작이 완료될떄까지 실행시간을 얻지 못하고 

기다리는 짧은 수명의 태스크가 있을 수 있다.


반면 너무 많은 스레드도 CPU가 실행 대신 스레드의 전환에 많은 시간을 사용해야하므로 성능에 부정적인 영향을 미칠 수 있다.


스레드 풀의 크기는 하부의 하드웨어, 좀더 정확히말해 사용가능한 CPU 개수를 기준으로 하는것이 좋다. 안드로이드는 Runtime 클래스에서 CPU개수를 알아낼 수 있다.


int N  = Runtime.getRuntume().availableProcessors();


N은 실제로 동시에 실행될 수 있는 태스크의 최대 개수다.


스레드 풀의크기 N은 독립적이고 비차단적인 태스크들의 운용하기에 충분할수있다.

(고도의 연산을 요하는등)



역동성



제한 또는 무제한 태스크 큐

스레드풀은 일반적으로 제한 또는 무제한 태스크 큐와 함꼐 사용한다.

무제한 큐는 무한증가할 수 있어서 메모리가 고갈할 수 있는 반면, 제한 큐의 자원소비는

더 잘관리될 수 있다 한편 제한 큐는 그 크기와 포화정책을 모두 준비해야하낟.

포화정책이란 거부된 태스크를 생산자가 어떻게 처리할지를 뜻한다.



제한 또는 무제한의 큐를 구현한 것이 LinkedBlockingQueue, PriorityBlockingQueue, ArrayBlockingQueue다.

뒤의 두가지 큐는 제한 큐고, 첫번째 큐는 기본적으로 무제한 큐지만 제한 큐로 구성할 수 있다.


+ Recent posts