3

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

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416

2 Answers2

3

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.

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
  • If I make the `random` and `server` variables **static** in [MyRunnable.java](https://github.com/afarber/jetty-newbie/tree/master/TlsPskServer2/src/main/java/de/afarber/tlspskserver2) and have 10 instances of that class - won't they be used by all 10 instances? I am curious why do you suggest **static** here? Because what I need is 10 pre-allocated `SecureRandom` and `MockPSKTlsServer` instances for each thread in my pool... – Alexander Farber Nov 18 '16 at 12:43
  • 1
    No it must be **static** otherwise your `ThreadLocal` would be useless. You should read the javadoc about a `ThreadLocal`, in a nutshell a `ThreadLocal` is used to scope an instance of a given class to a `Thread`, in other words what thread 1 will get from the `ThreadLocal` will be different from what thread 2 will get. So if you have 10 threads calling `get()` on the `ThreadLocal`, the `ThreadLocal` will actually manage 10 instances of your class (one per thread). – Nicolas Filotto Nov 18 '16 at 12:52
2

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/

Nim
  • 33,299
  • 2
  • 62
  • 101
  • Actually I don't communicate with other threads. I read incoming data, decrypt it and close the socket. In the long term I would like to forward the decrypted data to an embedded Jetty (which can't [TLS PSK](https://en.wikipedia.org/wiki/TLS-PSK)) through another socket. I.e. I am trying to program a thread-pooled "reverse proxy" for Jetty. – Alexander Farber Nov 18 '16 at 12:28
  • Well, you don't need a pool then, looks like you only need a single instance - in this case - ignore the stuff about pool and stick it in a `ThreadLocal<>` directly.. – Nim Nov 18 '16 at 12:30