如何为线程池服务器预分配对象?
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
使用的 SecureRandom
和 MockPSKTlsServer
对象?
即如何在 main()
中创建两个对象中的 10 个,然后在 run()
中重用它们?
通常我会使用 ThreadLocal<>
并使用轻量级 Pool<T>
class 来保存和提供实例。
我认为没有开箱即用的 Pool<T>
,但它的构造很简单。
使用 ThreadLocal<>
的唯一考虑是您必须确保正确释放回 Pool<>
。因此,如果您正在考虑将其与另一个线程进行通信,更好的方法可能是共享的静态池,但可以使用锁定(如果您不太关心性能)或并发容器(如果您这样做的话)..
在你的情况下,我会为每个 class(SecureRandom
和 MockPSKTlsServer
)使用一个 ThreadLocal
,以获得一个 SecureRandom
和MockPSKTlsServer
用于连接池的每个线程,并在线程必须执行相同类型的任务但输入不同时重用它们 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 流。
在 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
使用的 SecureRandom
和 MockPSKTlsServer
对象?
即如何在 main()
中创建两个对象中的 10 个,然后在 run()
中重用它们?
通常我会使用 ThreadLocal<>
并使用轻量级 Pool<T>
class 来保存和提供实例。
我认为没有开箱即用的 Pool<T>
,但它的构造很简单。
使用 ThreadLocal<>
的唯一考虑是您必须确保正确释放回 Pool<>
。因此,如果您正在考虑将其与另一个线程进行通信,更好的方法可能是共享的静态池,但可以使用锁定(如果您不太关心性能)或并发容器(如果您这样做的话)..
在你的情况下,我会为每个 class(SecureRandom
和 MockPSKTlsServer
)使用一个 ThreadLocal
,以获得一个 SecureRandom
和MockPSKTlsServer
用于连接池的每个线程,并在线程必须执行相同类型的任务但输入不同时重用它们 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 流。