Name: boT120536 Date: 04/02/2001
C:\>java -version
java version "1.2.2"
Classic VM (build JDK-1.2.2-001, native threads, symcjit)
If threading a built-in feature of the java language, why isn't there a simple,
basic object that performs thread pooling? There ought to be, programmers
shouldn't have to write their own thread pools from scratch every time; we
should have a basic ThreadPool object that's part of the standard JDK that we
can extend (or perhaps part of the J2EE maybe), even if it's an abstract class
and can't be instantiated directly. (You guys also ought to write a standard DB
connection pool that can be extended, too.)
When I say "thread pool", I'm referring to an object that instantiates a
bunch of threads, gets them initialized and started, and then puts them to
sleep. For instance, if you were to write a web server, you'd want to assign
a thread to handle each client request (WebLogic does this, for example).
Since you expect a lot of client requests, you wouldn't want to instantiate
a thread for each one when that request came in -- if a bunch of requests
came in at the same time, there's be a noticable performance problem while
you were instantiating a bunch of threads and starting them to process each
request. With a thread pool, you just pull one out of the pool, assign it to
handle the task, and wake it up.
Source Listing for ThreadPool.java:
----
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class ThreadPool
{
// these two Sets make up the pool of threads
// while a thread is executing, it cannot be
// assigned other tasks, so it's removed from
// the idle List and placed in the busy List
private List idle;
private List busy;
// this is where a thread picks up the task it's
// supposed to start executing
private Runnable handoffBox;
// when a ThreadPool is constructed, it initializes
// all of the threads and puts them to sleep until a
// task comes in to be run on one of them
public ThreadPool( int size ) {
idle = Collections.synchronizedList( new LinkedList(size) );
busy = Collections.synchronizedList( new LinkedList(size) );
Runnable initThread = new Runnable() {
public void run() {
Runnable task;
synchronized( handoffBox ) {
while( handoffBox == null ) {
handoffBox.wait(); // puts thread to sleep
}
// transfer reference to task out of handoffBox
task = handoffBox;
handoffBox = null;
}
// move this worker from the idle pool to the
// busy pool
Thread thisThread = Thread.currentThread();
idle.remove( thisThread );
busy.add( thisThread );
// execute the task
try {
task.run();
}
catch( Throwable t ) {
// something went wrong -- do something
}
finally {
// put this worker thread back in idle pool
busy.remove( thisThread );
idle.add( thisThread );
}
}
for( int i=0; i < size; i++ ) {
Thread worker = new Thread( initThread );
idle.add( worker );
worker.start();
}
}
// this method causes the task to be executed
// from the context of one of the worker threads
public void dispatch( Runnable task ) {
if( idle.isEmpty() ) {
// all worker threads busy. wait for one to become
// available, or throw an exception, or something
}
synchronized( handoffBox ) {
handoffBox = task;
// wake up any thread in the idle pool and have
// it pick up this task from the handoffBox.
// it will move itself to the busy pool and
// back to the idle pool when it's done.
handoffBox.notify();
}
}
}
This is a very simple, stupid implementation of a thread pool, but it shows
how one of these thread pools might work. Obviously, if one were to be
placed in the JDK, it would have to be a bit more robust. It would have to
allow a worker thread to be interruptible, for instance. Also, instead of
just having a handoffBox, there could be a FIFO Runnable queue instead, and
threads in the idle pool would pull tasks off the queue. That way, if there
were no idle threads tasks would just accumulate in the queue until the
threads finished what they were doing and became available. Another addition
to a standard threadpool might be a mechanism that assigns a priority to the
task -- the threads executing more important tasks would have their
priorities set appropriately. Instead of having a busy list and an idle
list, you could use an idle list and a bunch of busy lists -- each busy list
would contain threads of similar priority. The ThreadPool could also be
growable from its initial capacity to some max capacity, by specified
increments. If all the threads available were used, the pool would
automatically allocate new threads up to some max. Similarly, instead of
calling just "wait()" when they sleep, they could pass some timeout to the
wait() operation. This way, any thread that times out after not being used
for 10 minutes (or whatever the timeout is -- this could be specified at
construction time) could be dynamically downsized.
Every company I've ever worked for that builds a system that is
multithreaded ends up implementing their own thread pool. This is kind of
like forcing programmers to implement their own hash table -- they could do
it, but the JDK can off-load this work and standardize it for everyone so
they don't have to waste time writing and debugging their own.
Similarly, a default means of handling database connections could be
provided with the JDK. Nearly every project that accesses a database uses a
connection pool so that the app doesn't have to initialize a new connection
every time it needs to get to the database. I'm not sure whether this would
be more appropriate as part of the J2EE stuff or the standard JDK, or maybe
as a standard extension package such as javax.util or something, but it
really is something that would be used frequently. With all the technology
that java provides, it's silly to force programmers to write and debug their
own thread pools and db connection pools when nearly every significant
project would use both.
(Review ID: 119802)
======================================================================