issue url
版本情况
hutool版本: 5
问题描述(包括截图)
参考文档构建代码:AIO封装-AioServer和AioClient
其中 AioClient
的示例如下:
public void foobar() { AioClient client = new AioClient(new InetSocketAddress("localhost", 8899), new SimpleIoAction() { @Override public void doAction(AioSession session, ByteBuffer data) { if(data.hasRemaining()) { Console.log(StrUtil.utf8Str(data)); session.read(); } Console.log("OK"); } }); client.write(ByteBuffer.wrap("Hello".getBytes())); client.read(); client.close(); }
|
若直接在生产环境调用此代码,将必然出现线程溢出 OOM
原因
见 AioClient
该类有三个构造方法:
public AioClient(InetSocketAddress address, IoAction<ByteBuffer> ioAction)
public AioClient(InetSocketAddress address, IoAction<ByteBuffer> ioAction, SocketConfig config)
public AioClient(AsynchronousSocketChannel channel, IoAction<ByteBuffer> ioAction, SocketConfig config)
前两个方法都会默认调用 private static AsynchronousSocketChannel createChannel(InetSocketAddress address, int poolSize)
隐含构建线程池
但在 AioClient
的close
方法中,线程池没有被关闭。反复通过上述示例代码进行调用后,线程池可能会膨胀到非常夸张的地步,直到内存不足产生OOM。
正确示例
正确的方式是只构建一个 AsynchronousChannelGroup
,并反复使用。在不需要时,进行关闭。
private static final AsynchronousChannelGroup GROUP = AsynchronousChannelGroup.withFixedThreadPool( Runtime.getRuntime().availableProcessors(), ThreadFactoryBuilder.create().setNamePrefix("Huool-socket-").build() );
public static void closeAioGroup() throws IOException { GROUP.shutdown(); }
private static AsynchronousSocketChannel createChannel(InetSocketAddress address) {
AsynchronousSocketChannel channel; try { channel = AsynchronousSocketChannel.open(group); } catch (IOException e) { throw new IORuntimeException(e); } try { channel.connect(address).get(); } catch (InterruptedException | ExecutionException e) { IoUtil.close(channel); throw new SocketRuntimeException(e); } return channel; }
public void foobar() { AioClient client = new AioClient(createChannel(new InetSocketAddress("localhost", 8899)), new SimpleIoAction() { @Override public void doAction(AioSession session, ByteBuffer data) { if(data.hasRemaining()) { Console.log(StrUtil.utf8Str(data)); session.read(); } Console.log("OK"); } }); client.write(ByteBuffer.wrap("Hello".getBytes())); client.read(); client.close(); }
|
建议
- 建议更新文档,防止因按文档使用导致
OOM
- 建议标记另两个构造方法为过时的,且打印日志提醒不能在生产环境使用