5

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.)

Community
  • 1
  • 1
Michael
  • 347
  • 2
  • 13
  • Is it possible that each request is handled fast enough where the executor is able to keep reusing the same thread? Can you add some delay into your handler to see if anything changes? – Eric Levine Aug 06 '13 at 15:20
  • @elevine: I thought about that, so added a `Thread.sleep(1000)` to TestHandler.handle(HttpExchange). Same result. Thanks. – Michael Aug 06 '13 at 15:36

1 Answers1

3

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.

Community
  • 1
  • 1
Josep Panadero
  • 3,042
  • 1
  • 16
  • 10
  • I have a similar issue where the ThreadId changes but I am getting that the attributes I set in the Filter (inside the `HttpExchange` object) I have designed are not being kept to the actual handler when I have a lot of requests concurrently. Instead some data is being lost and overwritten by other http exchanges instances of other threads. Any help will be really appreciated. – Miguelme May 15 '20 at 22:32