Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get HttpServer to create multiple HttpHandlers in parallel?

Tags:

java

http

I'm using com.sun.net.httpserver.HttpServer to create a small container for testing bits of server code and am having trouble getting it to use more than one thread to handle requests.

I call java.util.concurrent.Executors.newFixedThreadPool(20) to create a java.util.concurrent.ThreadPoolExecutor with 20 threads. Then, I set this Executor on the HttpServer. Using Jmeter, I fire off 20 client threads to send a request to be routed to the only HttpHandler implementation in the server. That handler does a System.out.println(this) and I'm seeing this output:

Started TestServer at port 8800
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa
http.TestHandler@30eb9dfa

I thought I would see 20 (or nearly 20) different threads being used here. Here's the code.

package http;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class TestServer implements Runnable {

    private final static int PORT    = Integer.getInteger("test.port", 8800); 
    private static TestServer serverInstance;
    private HttpServer        httpServer;
    private ExecutorService   executor;

    @Override
    public void run() {
        try {
            executor = Executors.newFixedThreadPool(20);

            httpServer = HttpServer.create(new InetSocketAddress(PORT), 0);
            httpServer.createContext("/test", new TestHandler());
            httpServer.setExecutor(executor);
            httpServer.start();
            System.out.println("Started TestServer at port " + PORT);

            // Wait here until notified of shutdown.
            synchronized (this) {
                try {
                    this.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    static void shutdown() {

        try { 
            System.out.println("Shutting down TestServer.");            
            serverInstance.httpServer.stop(0);

        } catch (Exception e) {
            e.printStackTrace();
        }

        synchronized (serverInstance) {
            serverInstance.notifyAll();
        }

    }

    public static void main(String[] args) throws Exception {

        serverInstance = new TestServer();

        Thread serverThread = new Thread(serverInstance);
        serverThread.start();

        Runtime.getRuntime().addShutdownHook(new OnShutdown());

        try {
            serverThread.join();
        } catch (Exception e) { }
    }

}

/* Responds to the /test URI. */
class TestHandler implements HttpHandler {

    boolean debug = Boolean.getBoolean("test.debug");

    public void handle(HttpExchange exchange) throws IOException {

        System.out.println(this);  // ALWAYS SAME THREAD!

        String response = "RESPONSE AT " + System.currentTimeMillis();

        exchange.sendResponseHeaders(200, response.length());
        OutputStream os = exchange.getResponseBody();
        os.write(response.getBytes());
        os.flush();
        os.close();
    }
}

/* Responds to a JVM shutdown by stopping the server. */
class OnShutdown extends Thread {
    public void run() {
        TestServer.shutdown();
    }
}

I'd like the HttpServer to create multiple TestHandlers in parallel to service the multiple simultaneous requests. What am I missing here?

(BTW, this is quite similar to Can I make a Java HttpServer threaded/process requests in parallel?, though the answer to that is to use an Executor, which I am already doing. thanks.)

like image 745
Michael Avatar asked Nov 02 '22 17:11

Michael


1 Answers

The same instance of a runnable can be run multiple times in different threads. See Initializing two threads with the same instance of a runnable for more info.

What you are printing in your example is the HttpHandler information but nothing about in which thread is running. And that information doesn't changes as the server reuses always the same object for all threads.

If you want to print the thread id you can use:

long threadId = Thread.currentThread().getId();
System.out.println(threadId);

threadId should change as expected.

like image 64
Josep Panadero Avatar answered Nov 15 '22 05:11

Josep Panadero