Multi-threading is a good thing but it's still not a perfect
solution. For example, let's take a look at the accept loop of the
ThreadedEchoServer
:
while (true) {
try {
Socket s = ss.accept();
ThreadedEchoServer tes = new ThreadedEchoServer(s);
tes.start();
}
catch (IOException ex) {
}
Every time you pass through this loop, a new thread gets created. Every time a connection is finished the thread is disposed of. Spawning a new thread for each connection takes a non-trivial amount of time, especially on a heavily loaded server. It would be better not to spawn so many threads.
An alternative approach is to create a pool of threads when the
server launches, store incoming connections in a queue, and have
the threads in the pool progressively remove connections from the
queue and process them. This is particularly simple since the
operating system does in fact store the incoming connections in a
queue. The main change you need to make to implement this is to
call accept()
in the run()
method rather
than in the main()
method. The program below
demonstrates.
import java.net.*;
import java.io.*;
public class PoolEchoServer extends Thread {
public final static int defaultPort = 2347;
ServerSocket theServer;
static int numberOfThreads = 10;
public static void main(String[] args) {
int port = defaultPort;
try {
port = Integer.parseInt(args[0]);
}
catch (Exception ex) {
}
if (port <= 0 || port >= 65536) port = defaultPort;
try {
ServerSocket ss = new ServerSocket(port);
for (int i = 0; i < numberOfThreads; i++) {
PoolEchoServer pes = new PoolEchoServer(ss);
pes.start();
}
}
catch (IOException ex) {
System.err.println(ex);
}
}
public PoolEchoServer(ServerSocket ss) {
theServer = ss;
}
public void run() {
while (true) {
try {
Socket s = theServer.accept();
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream();
while (true) {
int n = in.read();
if (n == -1) break;
out.write(n);
out.flush();
} // end while
} // end try
catch (IOException ex) {
}
} // end while
} // end run
}
In the program above the number of threads is set to ten. This can be adjusted for performance reasons. How would you go about testing the performance of this program relative to the one that spawns a new thread for each connection? How would you determine the optimum number of threads to spawn?