根据java api,InputStream.read()
描述为:
如果由于到达流末尾而没有可用字节,则返回值-1.此方法将阻塞,直到输入数据可用,检测到流的末尾或抛出异常.
我有一个while(true)
循环执行读取,当通过流发送任何内容时,我总是得到-1.这是预期的.
我的问题是什么时候会读取()阻止?因为如果它没有获得任何数据,则返回-1.我希望阻塞读取等到收到数据.如果你已经到达输入流的末尾,不应该读取()只是等待数据而不是返回-1?
或者read()只阻止是否有另一个线程访问流并且你的read()无法访问流?
这引出了我的下一个问题.我曾经有过事件监听器(由我的库提供),当数据可用时会通知我.当我收到通知时,我会调用while((aByte = read()) > -1)
存储字节.当我在非常接近的时间内收到两个事件并且我的所有数据都没有被显示时,我感到很困惑.似乎只显示第二个事件数据的尾端,其余部分丢失了.
我最终改变了我的代码,以便当我得到一个事件时,我会调用if(inputStream.available() > 0) while((aByte = read()) > -1)
存储字节.现在它正常工作,我的所有数据都显示出来了.
有人可以解释这种行为吗?该InputStream.available()
是说要回,你可以阻止下一个调用方之前读取的字节数(流?).即使我不使用.available(),我希望第一个事件的读取只是阻止第二个事件的读取,但不会擦除或消耗过多的流数据.为什么这样做会导致我的所有数据都不显示?
某些实现的基础数据源InputStream
可以表示已到达流的末尾,并且不会再发送数据.在接收到该信号之前,对这种流的读操作可能会阻塞.
例如,InputStream
一个Socket
套接字将阻塞而不是返回EOF,直到收到一个设置了FIN标志的TCP数据包.当从这样的流接收到EOF时,可以确保在该套接字上发送的所有数据都已被可靠地接收,并且您将无法再读取任何数据.(如果阻塞读取导致异常,另一方面,某些数据可能已丢失.)
其他流(如来自原始文件或串行端口的流)可能缺少类似的格式或协议,以指示不再有可用的数据.当没有数据当前可用时,这些流可以立即返回EOF(-1)而不是阻塞.但是,如果没有这样的格式或协议,您无法确定对方何时完成发送数据.
关于你的第二个问题,听起来你可能有一个竞争条件.没有看到有问题的代码,我猜这个问题实际上存在于你的"显示"方法中.也许第二次通知显示的尝试在某种程度上破坏了第一次通知期间完成的工作.
如果它是流的结束,则返回-1.如果流仍处于打开状态(即套接字连接),但没有数据到达读取端(服务器速度慢,网络速度慢......)read()阻塞.
您不需要可用的呼叫().我很难理解您的通知设计,但除了read()本身之外,您不需要任何调用.可用方法()仅为方便起见.
好吧,这有点乱,所以首先要澄清一下:InputStream.read()阻塞与多线程无关.如果您有多个线程从同一输入流读取并且您触发两个彼此非常接近的事件 - 每个线程尝试使用一个事件然后您就会损坏:第一个要读取的线程将获得一些字节(可能全部字节),当第二个线程被调度时,它将读取剩余的字节.如果计划在多个线程中使用单个IO流,则始终在某些外部约束上进行同步.
其次,如果您可以从InputStream中读取,直到获得-1然后等待并且稍后可以再次读取,那么您正在使用的InputStream实现就会被破坏!InputStream的契约清楚地表明,当没有更多的数据要读取时,InputStream.read()应该只返回-1,因为已经到达了整个流的末尾,并且没有更多的数据可用 - 就像你从一个文件,你到达终点.
"现在没有更多数据,请等待,你会得到更多"的行为是read()阻塞,直到有一些数据可用(或抛出异常)才返回.
默认情况下,提供的RXTX InputStream的行为不符合要求.
您必须将接收阈值设置为1并禁用接收超时:
serialPort.enableReceiveThreshold(1); serialPort.disableReceiveTimeout();
来源:RXTX串行连接 - 阻塞读取问题()