0

有没有办法让 java 中的一个线程对某些 FileInputStream 或类似内容进行读取调用,并让第二个线程同时处理正在加载的字节?我已经尝试了很多事情 - 我目前的尝试有一个线程运行这个:

FileChannel inStream;
try {
   inStream = (new FileInputStream(inFile)).getChannel();
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
int result;
try {
     result = inStream.read(inBuffer);
} ...

第二个线程想要在加载字节时访问它们。显然,第一个线程中的读取调用会阻塞,直到缓冲区已满,但我希望能够在该点之前访问加载到缓冲区中的字节。目前,我尝试的所有内容都有缓冲区,并且它的支持数组在读取完成之前保持不变 - 这不仅破坏了这个线程的要点,而且还表明数据正在某个地方加载到某个中间缓冲区,然后稍后复制到我的缓冲区中,这似乎愚蠢。

一种选择是对数组进行一系列较小的读取,并在后续读取时使用偏移量,但这会增加额外的开销。

有任何想法吗?

4

4 回答 4

3

当您顺序读取数据时,操作系统会在您需要数据之前提前读取数据。由于系统已经为您执行此操作,您可能无法获得预期的好处。

为什么我不能让我的 Filechannel 或 FileInputStream “流动”到我的 ByteBuffer 或某个字节数组中?

这就是它已经在做的事情。

如果您想要更无缝地加载数据,您可以使用内存映射文件,因为它立即“出现”在程序的内存中,并在您使用它时在后台加载。

于 2012-08-02T20:30:17.160 回答
1

我建议使用SynchronousQueue。读取器将从队列中检索数据,写入器将从您的文件中“发布”数据。

于 2012-08-02T20:45:21.127 回答
1

我通常对这样的要求做的是使用多个缓冲区类实例,最好调整大小以允许有效加载 - 例如集群大小的倍数。一旦第一个缓冲区加载完毕,就将其排入队列(即将其指针/实例推送到生产者-消费者队列中)到将处理它的线程并立即创建(或解池)另一个缓冲区实例和开始加载那个。为了控制整体数据流,您可以在启动时创建适当数量的缓冲区对象并将它们存储在“池队列”(另一个生产者-消费者队列)中,然后您可以从池中循环充满数据的对象,以文件读取线程,然后到缓冲区处理线程,然后返回池。

这使文件->处理队列“充满”缓冲区对象充满数据,不需要批量复制,没有不可避免的延迟,没有单字节的低效线程间通信,没有混乱的缓冲区索引锁定,没有机会文件读取线程和数据处理线程可以对同一个缓冲区对象进行操作。

如果您想/需要使用 threadPool 来执行处理,您可以轻松地执行此操作,但如果您需要此子系统的任何结果输出与读取的顺序相同,则可能需要缓冲区对象中的序列号从文件中。

缓冲区对象还可能包含结果数据成员、异常/错误消息字段以及您可能想要的任何内容。在重新汇集之前,文件和/或结果数据可以很容易地从数据处理转发到其他线程(例如,记录器或进度的 GUI 显示)。由于这只是指针/实例队列,因此大量数据将在您的系统中快速有效地流动。

于 2012-08-02T21:26:20.530 回答
0

使用 PipedInput/OutputStream 创建一个熟悉的带有缓冲区的管道。

如有必要,还可以使用 FileInputStream 逐字节读取它。fis.read() 函数不会阻塞,如果没有数据,它将返回 -1,您可以随时检查 available();

于 2012-08-02T20:56:01.413 回答