Search code examples
javasslthreadpoolbouncycastletls-psk

How to preallocate objects for thread pooled server?


In a simple test case I have implemented a thread pooled server accepting up to 10 simultaneous incoming TLS PSK connections at port 12345 and printing decrypted data at standard output:

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

Here is the Runnable implementation used by the threads:

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

How to preallocate the SecureRandom and MockPSKTlsServer objects used by the Runnable?

I.e. how to create 10 of both objects in the main() and then just reuse them in the run()?


Solution

  • In your case I would use a ThreadLocal for each class (SecureRandom and MockPSKTlsServer), to have one dedicated instance of SecureRandom and MockPSKTlsServer for each thread of your connection pool and reuse them when the threads will have to execute the same type of task but with different input Socket, something like:

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

    NB: Use the try-with-resources statement to automatically close your input/output streams.