我正在创建一个 RandomAccessFile
对象以通过多个线程写入文件(在 SSD 上)。每个线程都尝试在文件中的特定位置写入直接字节缓冲区,我确保线程写入的位置不会与另一个线程重叠:
file_.getChannel().write(buffer, position);
其中 file_
是 RandomAccessFile
的实例,buffer
是直接字节缓冲区。
对于 RandomAccessFile 对象,由于我没有使用 fallocate 分配文件,并且文件的长度在变化,这是否会利用底层媒体的并发性?
如果不是,在创建文件时不调用 fallocate 使用上述函数是否有意义?
最佳答案
我用下面的代码做了一些测试:
public class App {
public static CountDownLatch latch;
public static void main(String[] args) throws InterruptedException, IOException {
File f = new File("test.txt");
RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
Thread t = new Thread(new WritingThread(i, (long) i * 10, file.getChannel()));
t.start();
}
latch.await();
file.close();
InputStream fileR = new FileInputStream("test.txt");
byte[] bytes = IOUtils.toByteArray(fileR);
for (int i = 0; i < bytes.length; i++) {
System.out.println(bytes[i]);
}
}
public static class WritingThread implements Runnable {
private long startPosition = 0;
private FileChannel channel;
private int id;
public WritingThread(int id, long startPosition, FileChannel channel) {
super();
this.startPosition = startPosition;
this.channel = channel;
this.id = id;
}
private ByteBuffer generateStaticBytes() {
ByteBuffer buf = ByteBuffer.allocate(10);
byte[] b = new byte[10];
for (int i = 0; i < 10; i++) {
b[i] = (byte) (this.id * 10 + i);
}
buf.put(b);
buf.flip();
return buf;
}
@Override
public void run() {
Random r = new Random();
while (r.nextInt(100) != 50) {
try {
System.out.println("Thread " + id + " is Writing");
this.channel.write(this.generateStaticBytes(), this.startPosition);
this.startPosition += 10;
} catch (IOException e) {
e.printStackTrace();
}
}
latch.countDown();
}
}
}
到目前为止我所看到的:
Windows 7(NTFS 分区):线性运行(也就是一个线程写入,当它结束时,另一个线程开始运行)
Linux Parrot 4.8.15(ext4 分区)(基于 Debian 的发行版),带有 Linux Kernel 4.8.0:线程在执行期间混合
再次作为documentation说:
File channels are safe for use by multiple concurrent threads. The close method may be invoked at any time, as specified by the Channel interface. Only one operation that involves the channel's position or can change its file's size may be in progress at any given time; attempts to initiate a second such operation while the first is still in progress will block until the first operation completes. Other operations, in particular those that take an explicit position, may proceed concurrently; whether they in fact do so is dependent upon the underlying implementation and is therefore unspecified.
所以我建议首先尝试一下,看看您要将代码部署到的操作系统(可能是文件系统类型)是否支持并行执行 FileChannel.write
打电话
编辑:正如所指出的,以上并不意味着线程可以同时写入文件,它实际上是相反的,因为 write
调用的行为根据WritableByteChannel的契约(Contract)它清楚地指定一次只有一个线程可以写入给定文件:
If one thread initiates a write operation upon a channel then any other thread that attempts to initiate another write operation will block until the first operation is complete
关于java - Java中RandomAccessFile的并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45396252/