-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Example: Using a ThreadPool
Tom Howland edited this page May 14, 2016
·
4 revisions
You have this amazingly tiny web server that works perfectly! But wait, what happens when it gets a million simultaneous requests? Do you want to spin up a million threads? No. You want a thread pool. Something like this:
import fi.iki.elonen.NanoHTTPD;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
/**
* BoundRunner
* <p>
* The default threading strategy for NanoHTTPD launches a new thread every time. We override that here so we can put an
* upper limit on the number of active threads using a thread pool.
*/
class BoundRunner implements NanoHTTPD.AsyncRunner {
private ExecutorService executorService;
private final List<NanoHTTPD.ClientHandler> running =
Collections.synchronizedList(new ArrayList<NanoHTTPD.ClientHandler>());
public BoundRunner(ExecutorService executorService) {
this.executorService = executorService;
}
@Override
public void closeAll() {
// copy of the list for concurrency
for (NanoHTTPD.ClientHandler clientHandler : new ArrayList<>(this.running)) {
clientHandler.close();
}
}
@Override
public void closed(NanoHTTPD.ClientHandler clientHandler) {
this.running.remove(clientHandler);
}
@Override
public void exec(NanoHTTPD.ClientHandler clientHandler) {
executorService.submit(clientHandler);
this.running.add(clientHandler);
}
}
You use it with something like
import fi.iki.elonen.NanoHTTPD;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
/** App is a simple little web server with some constraints on the number of threads. */
public class App extends NanoHTTPD {
private static final Logger logger = Logger.getLogger(App.class.getName());
public App(int port) throws IOException {
super(port);
}
public static void main(String[] args) {
try {
Options options = new Options();
options.addOption("port", true, "port number to use");
options.addOption("web_threads", true, "maximum number of threads for the web server");
CommandLineParser parser = new BasicParser();
CommandLine cmd = parser.parse(options, args);
int port = Integer.parseInt(cmd.getOptionValue("port", "5375"));
int webThreads = Integer.parseInt(cmd.getOptionValue("web_threads", "10"));
App app = new App(port);
app.setAsyncRunner(new BoundRunner(Executors.newFixedThreadPool(webThreads)));
app.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
logger.info("waiting for connections on port " + port + " using a maximum of " +
webThreads + " web threads");
} catch (Throwable t) {
logger.log(Level.SEVERE, "Couldn't start server", t);
System.exit(1);
}
}
}