How to preallocate objects for thread pooled server?

302 Views Asked by At

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()?

2

There are 2 best solutions below

2
On BEST ANSWER

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.

2
On

Normally I would use a ThreadLocal<> and use a lightweight Pool<T> class to hold and provide the instances.

I don't think there is a Pool<T> out of the box, but this is trivially constructed.

The only consideration with ThreadLocal<> is you have to ensure that you release back to the Pool<> correctly. So if you are thinking of communicating this to another thread, a better approach may be a static pool that is shared, but either with locking (if you don't care too much about performance) or concurrent container if you do..

Having said that: http://commons.apache.org/proper/commons-pool/