. .
number of threads running at any one time. Should there be a sudden spike in the number of
requests, there will be an equal spike in the number of threads, causing performance degradation
due to the excessive number of threads competing for the same locks, CPUs, virtual memory, and
other resources. (Running this program on a fast 32-bit machine will crash the program when it
runs out of virtual memory.)
Rewriting the program to limit the number of threads would be somewhat ugly, and there are
better ways of handling the problem. This is probably not a good design for any program!
In the producer/consumer model (Code Example 12-8), the programmer can exert full control over
the number of threads with very little effort. The threads may be created at startup time and then
be left to wait for work to appear on the queue. Should some of the threads never run at all, there
will be no great cost-- probably immeasurable. Should there be too many incoming requests, they
can be placed on the queue and handled when convenient.
Example 12-8 Producer/Consumer Socket Design
public void startUp() throws Exception { // Executes in main thread
for (int i = 1; i < nConsumers; i++) {
Thread t = new Thread(new Consumer(workpile));
socket = serverSocket.accept();
Thread t = new Thread(new Producer(workpile, socket));
System.out.println("Server[" + t.getName() +
"]\tStarted new socket server: " + socket);
public static Request read(Socket socket) {
int n =;
return new Request(csocket, b);
An important aspect of the work queue is that you can allow the queue to grow to any length you
deem appropriate. If your clients block, waiting for the results of query 1 before issuing query 2,
then allowing the length of the queue to grow to the number of clients will assure you that requests
will never be lost, and you can maintain peak efficiency.
If clients are able to issue unlimited overlapping requests, you have no choice. At some point you
must begin rejecting requests. However, as long as the average rate of incoming requests is below
what your server can handle, then by allowing the queue to grow up to some modest limit, you can
effectively buffer burst traffic while retaining peak efficiency. This is a popular design and is the
general design of NFS.
The pipeline model is based directly on the same work model that is used in CPUs and on factory
floors. Each processing element will do a certain amount of the job and then pass the partially
completed task on to the next element (Code Example 12-9). Here the processing elements are
threads, of course, and each thread is going to do a portion of the task, then pass the partial results
on to the next thread.
Search WWH :
Custom Search
Previous Page
Multithreaded Programming with JAVA - Topic Index
Next Page
Multithreaded Programming with JAVA - Bookmarks