如何为线程池服务器预分配对象?
Posted
技术标签:
【中文标题】如何为线程池服务器预分配对象?【英文标题】:How to preallocate objects for thread pooled server? 【发布时间】:2016-11-18 12:09:33 【问题描述】:在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()
中重用它们?
【问题讨论】:
您使用哪个版本的 Java? 我在 Windows 和 Linux 上使用 Java SE 1.8 【参考方案1】:在您的情况下,我将为每个类(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
语句自动关闭您的输入/输出流。
【讨论】:
如果我在 MyRunnable.java 中创建random
和 server
变量 static 并拥有该类的 10 个实例 - 它们不会被所有 10 个实例使用?我很好奇你为什么在这里建议 static ?因为我需要为池中的每个线程预先分配 10 个 SecureRandom
和 MockPSKTlsServer
实例...
不,它必须是 static 否则您的 ThreadLocal
将毫无用处。您应该阅读有关 ThreadLocal
的 javadoc,简而言之,ThreadLocal
用于将给定类的实例范围限定为 Thread
,换句话说,线程 1 从 ThreadLocal
获得的内容会有所不同从线程 2 将得到什么。因此,如果您有 10 个线程在 ThreadLocal
上调用 get()
,则 ThreadLocal
实际上将管理您的类的 10 个实例(每个线程一个)。【参考方案2】:
通常我会使用 ThreadLocal<>
并使用轻量级 Pool<T>
类来保存和提供实例。
我认为没有开箱即用的Pool<T>
,但这只是简单的构造。
ThreadLocal<>
的唯一考虑是您必须确保正确释放回Pool<>
。因此,如果您正在考虑将其传达给另一个线程,更好的方法可能是共享静态池,但可以使用锁定(如果您不太关心性能)或并发容器(如果您这样做的话)......
话虽如此:http://commons.apache.org/proper/commons-pool/
【讨论】:
其实我不和其他线程通信。我读取传入的数据,解密并关闭套接字。从长远来看,我想通过另一个套接字将解密的数据转发到嵌入式 Jetty(不能TLS PSK)。 IE。我正在尝试为 Jetty 编写线程池“反向代理”。 好吧,你不需要一个池,看起来你只需要一个实例 - 在这种情况下 - 忽略关于池的东西并将它直接粘贴在ThreadLocal<>
中..跨度>
以上是关于如何为线程池服务器预分配对象?的主要内容,如果未能解决你的问题,请参考以下文章