5

com.sun.net.httpserver.HttpServer を使用して、サーバー コードのビットをテストするための小さなコンテナーを作成していますが、複数のスレッドを使用して要求を処理するのに問題があります。

java.util.concurrent.Executors.newFixedThreadPool(20) を呼び出して、20 個のスレッドを持つ java.util.concurrent.ThreadPoolExecutor を作成します。次に、この Executor を HttpServer に設定します。Jmeter を使用して、20 個のクライアント スレッドを起動し、サーバー内の唯一の HttpHandler 実装にルーティングされるリクエストを送信します。そのハンドラーは System.out.println(this) を実行し、次の出力が表示されます。

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

ここでは、20 (またはほぼ 20) の異なるスレッドが使用されていると思います。これがコードです。

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();
    }
}

複数の同時リクエストに対応するために、HttpServer で複数の TestHandler を並行して作成したいと考えています。ここで何が欠けていますか?

(ところで、これはCan I make a Java HttpServer threaded/process requests in parallel?と非常によく似ていますが、その答えは Executor を使用することですが、これは既に行っています。ありがとう。)

4

1 に答える 1

3

ランナブルの同じインスタンスを異なるスレッドで複数回実行できます。詳細については、ランナブルの同じインスタンスで 2 つのスレッドを初期化するを参照してください。

あなたの例で印刷しているのは HttpHandler 情報ですが、どのスレッドが実行されているかについては何もありません。サーバーはすべてのスレッドに対して常に同じオブジェクトを再利用するため、その情報は変更されません。

スレッド ID を出力したい場合は、以下を使用できます。

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

threadId は期待どおりに変更されるはずです。

于 2015-05-18T11:26:50.337 に答える