如何为线程池服务器预分配对象?

How to preallocate objects for thread pooled server?

a simple test case 中,我实现了一个线程池服务器,它在端口 12345 上接受最多 10 个同时传入的 TLS PSK 连接,并在标准输出上打印解密数据:

public static void main(String[] args) throws IOException {
    ServerSocket server  = new ServerSocket(12345);
    ExecutorService pool = Executors.newFixedThreadPool(10);

    while (true) {
        Socket socket = server.accept();
        pool.execute(new MyRunnable(socket));
    }
}

这是线程使用的 Runnable 实现:

@Override
public void run() {
    try {
        SecureRandom random      = new SecureRandom();       // How to preallocate?
        BufferedInputStream bis  = new BufferedInputStream(mSocket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(mSocket.getOutputStream());
        TlsServerProtocol proto  = new TlsServerProtocol(bis, bos, random);
        MockPSKTlsServer server  = new MockPSKTlsServer();   // How to preallocate?
        proto.accept(server);
        Streams.pipeAll(proto.getInputStream(), System.out);
        proto.close();
    } catch (IOException e) {
        System.err.print(e);
    }
}

如何预分配 Runnable 使用的 SecureRandomMockPSKTlsServer 对象?

即如何在 main() 中创建两个对象中的 10 个,然后在 run() 中重用它们?

通常我会使用 ThreadLocal<> 并使用轻量级 Pool<T> class 来保存和提供实例。

我认为没有开箱即用的 Pool<T>,但它的构造很简单。

使用 ThreadLocal<> 的唯一考虑是您必须确保正确释放回 Pool<>。因此,如果您正在考虑将其与另一个线程进行通信,更好的方法可能是共享的静态池,但可以使用锁定(如果您不太关心性能)或并发容器(如果您这样做的话)..

话虽如此:http://commons.apache.org/proper/commons-pool/

在你的情况下,我会为每个 class(SecureRandomMockPSKTlsServer)使用一个 ThreadLocal,以获得一个 SecureRandomMockPSKTlsServer 用于连接池的每个线程,并在线程必须执行相同类型的任务但输入不同时重用它们 Socket,例如:

private static final ThreadLocal<SecureRandom> random = ThreadLocal.withInitial(
    SecureRandom::new
);
private static final ThreadLocal<MockPSKTlsServer> server = ThreadLocal.withInitial(
    MockPSKTlsServer::new
);

...
public void run() {
    try (BufferedInputStream bis  = new BufferedInputStream(mSocket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(mSocket.getOutputStream());
        TlsServerProtocol proto  = new TlsServerProtocol(bis, bos, random.get())) {
        // Calling server.get() will get the instance dedicated to the current
        // thread, if no instance exists so far for this thread
        // new MockPSKTlsServer() will automatically be called then
        // affected to this thread for subsequent get's calls
        proto.accept(server.get());
        ...
    } catch (IOException e) {
        System.err.print(e);
    }
}

注意: 使用 try-with-resources 语句自动关闭您的 input/output 流。