java内存映射文件多线程读/写

时间:2015-07-16 11:39:39

标签: java multithreading memory-mapped-files mappedbytebuffer

我有2个线程同时访问同一个大文件(.txt)。

第一个线程正在从文件中读取。 第二个线程正在写入文件。

两个线程都访问同一个块,例如(开始:0,blockize:10),但不同的频道&缓冲实例

阅读器:

{
     int BLOCK_SIZE = 10;
     byte[] bytesArr = new byte[BLOCK_SIZE];
     File file = new File("/db.txt");
     RandomAccessFile randomFile = new RandomAccessFile(file, "r");
     FileChannel channel = randomFile.getChannel();
     MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, BLOCK_SIZE);
     map.get(bytesArr , 0, BLOCK_SIZE);
     channel.close();
}

编剧:

{
     int BLOCK_SIZE = 10;
     File file = new File("/db.txt");
     RandomAccessFile randomFile = new RandomAccessFile(file, "rw");
     FileChannel channel = randomFile.getChannel();
     MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, BLOCK_SIZE);
     map.put(bytesToWrite);
     channel.close();
}

我知道如果两者同时启动,我将获得重叠异常!但是我想知道的是,在什么时候重叠正好是什么?我的意思是什么时候发生“锁定”? 示例:假设编写者首先获得访问权限,然后如果读者尝试访问,那么可能在哪一点?:

 FileChannel channel = randomFile.getChannel();
 // 1- can reader access here?
 MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, BLOCK_SIZE);
 // 2- can reader access here?
 map.put(bytesToWrite);
 // 3- can reader access here?
 channel.close();
 // 4- can reader access here?

1,2,3或4?

No 4肯定,因为频道已关闭!其他几点呢?

谢谢!

2 个答案:

答案 0 :(得分:2)

我在与OP的聊天对话中总结了一些笔记。 OP具有心理模型(就像我们大多数人一样),一旦线程写入数据结构,该数据结构立即对所有其他线程可见。在使用内存映射文件的OP测试中,他已经确认在单个插槽Intel CPU上看起来是正确的。

不幸的是,这不是真的,并且Java可以并确实显示硬件的基本行为。 Java被设计为假设代码是单线程的,因此可以这样优化,直到它被告知为止。这意味着硬件和热点版本(以及热点收集的统计信息)会有所不同。这种复杂性,并在单个插槽上运行Intel CPU使OPs测试无效。

有关详细信息,以下链接将有助于深入了解“Java内存模型”。尤其是同步并不仅仅意味着“相互排斥”;在硬件方面,它还涉及“数据可见性”和“指令排序”。单线程代码认为理所当然的两个主题。

如果这需要时间沉入,并且您最初感到不知所措,请不要担心。起初我们都觉得这样。当且仅当你遵循这个简单的规则时,Java才能隐藏这种复杂性。当线程读取或修改共享数据结构时,它必须位于同步块内。也就是说,写作线程和阅读线程。显然我正在简化,但遵循该规则,程序将始终有效。只有当你对Java内存模型,内存障碍以及它与不同硬件的关系有很深的理解时才打破它(即使然后并发专家甚至可以避免违反规则;单线程通常要简单得多,可以是surprisingly fast ..因此,许多低延迟系统主要是单线程的。)

直接回答OP问题。问题中的示例代码没有锁定。没有内存障碍,根本没有并发控制。因此,读取和写入将如何交互的行为是不确定的。他们可能会工作,但他们可能不会。他们大部分时间都可以工作。英特尔拥有所有CPU的最强内存保证,并且在单个插槽上运行测试用例英特尔CPU将错过许多复杂的错误。在Java 5和JSR 133出现之前,Sun也被这个问题所困扰(阅读有关为什么双重检查锁定在Java中被破坏的文章以获取更多细节)。

答案 1 :(得分:1)

您不会从此代码或任何块中获取任何锁定异常。文件锁在进程之间而不是在线程之间运行。你需要的是同步,信号量或ReadWriteLocks。并且不需要使用两个频道。