多线程Java 8非阻塞读取是否存在争用条件?
现在这个问题困扰了我一段时间
在我工作的一个工作应用程序中,我在非阻塞模式下使用SocketChannel与嵌入式设备通信。 现在,我收到了零星损坏的数据。 在某些个人电脑上它不会发生,现在它发生在我的电脑上。 但当我在程序中更改太多时,问题就消失了
这么多可能会产生影响。时间,网络接口硬件,win7,java版本,公司防火墙
数据读取归结为以下代码:
byteBuffer.compact();
socketChannel.read(byteBuffer); // <<< problem here ?
byteBuffer.flip();
if( byteBuffer.hasRemaining() ){
handleData( byteBuffer );
}
当选择器唤醒并且设置了兴趣op_读取时,这与写入在同一线程中运行
此代码是引用byteBuffer的唯一位置。socketChannel仅在写入时从同一线程使用
我检测了代码,以便在错误发生时打印出最后几个read()调用的内容。同时分析了Wireshark上的网络流量。我添加了很多断言来检查bytebuffer的完整性
在Wireshark中,接收的流看起来不错。没有DUP-ACK或其他可疑的东西。最后的read()调用与Wireshark中的数据完全匹配
在Wireshark中,我看到许多小TCP帧以10毫秒的间隔接收90字节的有效负载数据。通常,Java线程在数据刚到达的10毫秒内读取数据
当涉及到这个问题时,Java线程有一点延迟,因为读取发生在300ms之后,读取返回大约3000字节,这是合理的。但是数据被破坏了
如果数据被复制到缓冲区,并且同时接收到的数据覆盖了第一个数据,则看起来像是这样
现在我不知道如何继续。我不能创建一个小例子,因为这种情况很少发生,我不知道需要的确切条件
有人能给个提示吗
我怎样才能证明它是不是Java库
哪些条件可能也很重要
谢谢 坦率的
2015年6月29日:
现在我能够为复制建立一个范例
发送方使用阻塞IO,首先等待连接,然后每2ms发送90字节的块。前4个字节是一个运行计数器,剩余的未设置。发送方使用setNoTcpDelay(true)
接收器使用非阻塞IO。首先,它连接到发送方,然后只要选择键准备就绪,它就会读取频道。有时,读循环执行一个线程。睡眠(300)
如果它们通过环回在同一台PC上运行,这对我一直都有效。如果我把发送器放在另一台通过局域网直接连接的PC上,就会触发错误。通过Wireshark的检查,发送的流量和数据看起来不错
要运行,首先在一台PC上启动发送方,然后(编辑主机地址后)启动接收方
只要有效,它大约每2秒打印一行。如果失败,它将打印关于最近5次read()调用的信息
我发现是触发因素:
- 发送方已配置setNoTcpDelay(true)
- 接收器有时有一根线。在执行读取()之前先睡眠(300)李>
谢谢 坦率的
# 1 楼答案
这是默认设置。把这个拿走
缓冲区已经空了,因为您刚刚分配了它。把这个拿走
在clear()和初始分配之后,限制已经为零。把这个拿走
这里应该有一个select()调用
此方法可能返回false。你不是在处理那个案子
完全不正确。您完全忽略了
read()
返回-1的情况,这意味着对等方已断开连接。在这种情况下,必须关闭通道所以呢?硬币不是掉了吗<移除睡眠<这完全是毫无意义的。在数据到达之前,
select()
将被阻塞。它不需要你的帮助。这种睡眠简直是浪费时间把这个拿走
这应该在循环的顶部,而不是底部
# 2 楼答案
我原来是个司机问题,至少看起来是这样
我使用USB到以太网适配器“D-Link E-DUB100 RevA”
由于wireshark显示了正确的数据,我认为消除硬件故障是一个可能的原因
但与此同时,我尝试了“D-Link E-DUB100 RevC1”,问题消失了
因此,我假设这是D-Link为Rev a提供的驱动程序中的一个问题。对于Rev C1,它可能使用一个没有这个问题的系统驱动程序
谢谢大家花时间阅读我的问题