我得到以下代码片段:
datagramChannel = DatagramChannel
.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true)
.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);
datagramChannel.configureBlocking(true);
datagramChannel.bind(new InetSocketAddress(filter.getType()
.getPort(filter.getTimeFrameType())));
datagramChannel.join(group, networkInterface);
datagramChannel.receive(buffer);
此代码位于Callable
中,我最多创建 12 Callable
秒(因此 12 个线程)以从 12 个不同的端口检索具有不同数据的组播数据包。它每 3-8 秒从网络上的信息中读取一次。
当连续汇集 12 个端口(等待信息、获取信息等)时,它会占用我 100% 的 CPU。
使用 JVisualVM 分析执行,我看到 90% 的执行时间都用于 java.nio.channels.DatagramChannel#receive()
,更准确地说是com.sun.nio.ch.DatagramChannelImpl#receiveIntoBuffer()
。
我不太明白为什么阻塞模式会消耗这么多 CPU。
我已经阅读了一些关于使用
Selector
s 而不是阻塞模式的文章,但我真的不明白为什么具有Selector
的while (true)
会比阻塞通道消耗更少。
问题是您在使用没有选择器的 NIO 时。
没有选择器的NIO可以使用,但是Channel.received会不断尝试读取,这将显示为一个线程的高CPU使用率。
有2种解决方案:-
- 使用选择器检测是否有要读取的内容。仅当选择器指示有要读取的数据时才调用通道。接收
- 使用 java.net.DatagramSocket/DatagramPacket 在阻塞模式下发送/接收。