Rather than spinning off threads for each and every task its recommended that you implement the work queue pattern. Its quite a simple idea, where you spin up a thread which sits around waiting on a semaphore to be posted to. Once the sema gets a post the thread goes and pulls an item out of the top of a vector and invokes execute() on it.
You can obviously implement this with a pool of worker threads waiting on the semaphore.
In your application code rather than creating new threads, you simply construct new WorkItem objects that implement the work item interface:
Code:
interface WorkItem {
void execute();
}
And add them to your work queue. The add method for your work queue should add the item to the Vector and post to the semaphore (releasing a thread to work on this item if its free). This isn't terribly different to spinning up a new thread from a coding perspective your just switching out 'extends Thread' with 'implements WorkItem' and renaming run as execute. This is of course once you've implemented the work queue classes/infrastructure.