我考虑过将文件加载到字节数组中,该数组由所有线程共享 - 每个线程将创建一个ByteArrayInputStream,但是分配一个1GB字节数组并不起作用。
我还考虑过使用单个FileChannel,每个线程使用Channels.newInputStream()在其上创建一个InputStream,但似乎是FileChannel维护了InputStream的状态。
如果想避免IO争用,看起来您需要将文件加载到内存中。操作系统会进行一些缓冲,但如果您发现这还不够,您就需要自己处理。
不过您真的需要32个线程吗?可能您没有那么多核心-使用较少的线程,您将获得更少的上下文切换等。
您的线程是否都从头到尾处理文件?如果是这样,您能否有效地将文件拆分成块?读取前10MB数据到内存中,让所有线程处理它,然后继续处理下一个10MB等。
如果以上方法对您没有用,您与文件大小相比有多少内存?如果您有足够的内存,但不想分配一个巨大的数组,您可以将整个文件读入内存,但分为许多单独的较小字节数组。然后,您必须编写跨越所有这些字节数组的输入流,但应该可行。
您可以以只读模式多次打开文件。您可以以任何方式访问文件。只需将缓存留给操作系统。当速度太慢时,您可能需要考虑某种基于块的缓存,所有线程都可以访问相同的缓存。
一些想法:
编写一个自定义的InputStream实现,作为FileChannel的视图。编写此类时,不应依赖于FileChannel中的任何状态。 (即:每个实例都应保持自己的位置,并且读取应在底层FileChannel上使用绝对读取。)这至少可以解决Channels.newInputStream()的问题,但可能无法解决IO争用问题。
编写一个自定义的InputStream实现,作为MappedByteBuffer的视图。内存映射不应该比一次性将整个文件读入内存更糟糕,但您仍会占用1GB的虚拟地址空间。
与#1相同,但具有某种共享缓存层。除非1被证明效率不够且2不可行,否则我不会尝试此方法。 实际上,在#1中,操作系统应该已经为您执行了一些缓存,因此在这里,您实际上正在尝试比操作系统文件系统缓存更聪明。
这是一个非常大的文件。你能否将文件分成一些较小的文件集进行传输?即使在企业网络上,仅传输此文件也将是一项巨大的工作。
有时候更改流程比更改程序更容易。
你甚至可以编写一些代码来将文件拆分成多个块并分别处理它们。