class WebServiceWithSharedServerSocket { public WebServiceWithSharedServerSocket(int nthreads) throws IOException { ServerSocket ss = new ServerSocket(...); for(i = 0; i < nthreads; ++i) (new Thread(new ConnectionHandler(ss))).start(); } } class ConnectionHandler implements Runnable { private final ServerSocket serverSocket; public ConnectionHandler(ServerSocket ss) { serverSocket = ss; } public void run() { while (!Thread.interrupted()) { try { Socket s = serverSocket.accept() // handle the request } catch (...) { // ... } } }Because blocking accepts from the ServerSocket behave in the same way as taking a task from a blocking channel serving as a workqueue, there is no reason to create your own Channels relayed from the host unless the host must play a role in dispatching, monitoring, or otherwise managing threads or requests. This is almost always more efficient, although harder to control. For example, dealing with cancellation of the service can be more challenging.
In some cases, it is possible to accommodate some Host intervention and management by centralizing the accept point, and surrounding it with additional processing performed under synchronization. For example, you could include code to possibly expand the pool (further extensions can be added to dynamically shrink it as well):
class WebServiceWithSharedAccept { private final ServerSocket serverSocket; private final int minthreads; private final int maxthreads; private int nthreads; public WebServiceWithSharedAccept(int mints, in maxt) throws IOException { minthreads = mint; maxthreads = maxt; nthreads = mint; serverSocket = new ServerSocket(...); for(i = 0; i < nthreads; ++i) (new Thread(new ConnectionHandler(this))).start(); } synchronized Socket accept() throws IOException { Socket s = serverSocket.accept(); // upon connection, possibly increase pool size if (nthreads < maxthreads) { ++nthreads; (new Thread(new ConnectionHandler(this))).start(); } return s; } } class ConnectionHandler implements Runnable { private WebServiceWithSharedAccept host; public ConnectionHandler(WebServiceWithSharedAccept h) { host = h } public void run() { while (!Thread.interrupted()) { try { Socket s = host.accept() // handle the request } catch (...) { // ... } } }
Discussions of message passing in distributed systems can be found in the sources listed in §1.2.5. Any of several packages and frameworks can be used to extend the techniques discussed here to apply in distributed contexts. For example, most of these designs (as well as most in §4.2 and elsewhere in this book) can be adapted for use in JavaSpaces. Conversely, many distributed message passing techniques can be scaled down to apply in concurrent, non-distributed settings. Design and implementation using JavaSpaces is discussed in:
A discussion of threads and futures in Swing, along with sample code, can be found in an article by Joe Bowbeer at the Swing Connection: The Last Word in Swing Threads
Thanks to Miles Sabin for comments and suggestions.