프로그래밍/프로그래밍팁

JDK 1.5 부터 등장한 ThreadPool

Terry Cho 2008. 2. 27. 14:12
Thread Pool이라는 것이 얼핏 생각하면 구현이 간단할 수 도 있지만, 막상 구현하려면 상당히 귀찮은데, JDK 1.5에 이 내용이 포함되어 있다.
상당히 설계도 잘한것 같아서 마음에 드는데..
이정도면 쉽게 웹서버정도는 만들 수 있지 않을까?

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html#execute(java.lang.Runnable)

생성자를 잠깐 살펴보면

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

* corePoolSize : Pool의 MIN크기
* maximumPoolSize : Pool의 MAX 크기
* keepAliveTime : Thread가 Idle이고 현재 전체 쓰레드수가 corePoolSize보다 많을때, 이 시간동안 Idle한 쓰레드는 없어진다. (Thread shirinking)
* keepAliveTime 단위
* workQueue : 쓰레드 풀에 대한 큐.
큐잉을 안하는 방법도 있고,
여러가지 정책이 있는데
Queuing
Any BlockingQueue may be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing:
  • If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
  • If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
  • If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
There are three general strategies for queuing:
  1. Direct handoffs. A good default choice for a work queue is a SynchronousQueue that hands off tasks to threads without otherwise holding them. Here, an attempt to queue a task will fail if no threads are immediately available to run it, so a new thread will be constructed. This policy avoids lockups when handling sets of requests that might have internal dependencies. Direct handoffs generally require unbounded maximumPoolSizes to avoid rejection of new submitted tasks. This in turn admits the possibility of unbounded thread growth when commands continue to arrive on average faster than they can be processed.
  2. Unbounded queues. Using an unbounded queue (for example a LinkedBlockingQueue without a predefined capacity) will cause new tasks to be queued in cases where all corePoolSize threads are busy. Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn't have any effect.) This may be appropriate when each task is completely independent of others, so tasks cannot affect each others execution; for example, in a web page server. While this style of queuing can be useful in smoothing out transient bursts of requests, it admits the possibility of unbounded work queue growth when commands continue to arrive on average faster than they can be processed.
  3. Bounded queues. A bounded queue (for example, an ArrayBlockingQueue) helps prevent resource exhaustion when used with finite maximumPoolSizes, but can be more difficult to tune and control. Queue sizes and maximum pool sizes may be traded off for each other: Using large queues and small pools minimizes CPU usage, OS resources, and context-switching overhead, but can lead to artificially low throughput. If tasks frequently block (for example if they are I/O bound), a system may be able to schedule time for more threads than you otherwise allow. Use of small queues generally requires larger pool sizes, which keeps CPUs busier but may encounter unacceptable scheduling overhead, which also decreases throughput.

일반적으로 LinkedBlockingQueue를 사용하면 문제는 없을듯하고, Queue의 MAX길이를 지정하고, QueueFull 시에 충분한 Exception 처리를 해주는것이 좋을듯하고
- threadFactory : 풀 크기를 느릴때 생성되는 쓰레드를 생성하는 팩토리
- handler : 풀이나 큐가 차서 처리를 못할때, Reject에 대한 처리를 하는 Handler

실제 Q에서 작업을 꺼내와서 수행하는 방법은
execute(Runnable r)을 사용하면 되고

흥미로운것은 (Hooking)
execute 전후에 훅킹 메서드를 beforeExecute,afterExecute를 넣을 수 있다는 것

그리드형

'프로그래밍 > 프로그래밍팁' 카테고리의 다른 글

Work load manager in JEE  (0) 2008.02.29
NIO  (0) 2008.02.27
SQL Batch  (0) 2007.11.28
대용량 Record select  (0) 2007.11.28
Java Application의 Locking 처리문제  (0) 2007.08.21