Ответ 1
Я провел несколько тестов со следующим кодом:
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: потоки перемежаются во время выполнения
Опять же, как документация говорит:
Файловые каналы безопасны для использования несколькими параллельными потоками. метод close может быть вызван в любое время, как указано в канале интерфейс. Только одна операция, которая включает в себя позицию канала или может изменить размер своего файла, может быть в любой момент; попытки инициировать вторую такую операцию, в то время как первая по-прежнему будет выполняться до тех пор, пока не завершится первая операция. Другие операции, в частности те, которые занимают явное положение, могут продолжаться одновременно; действительно ли они на самом деле зависят от и поэтому не указывается.
Итак, я бы предложил сначала попробовать и посмотреть, будут ли OS развертывать ваш код (возможно, тип файловой системы) для параллельного выполнения вызова FileChannel.write
Изменить. Как указано выше, вышеизложенное не означает, что потоки могут писать одновременно с файлом, это фактически противоположно тому, как вызов write
ведет себя в соответствии с контрактом WritableByteChannel, в котором четко указано, что только один поток за один раз может записать в данный файл:
Если один поток инициирует операцию записи по каналу, то любой другой поток, который пытается инициировать другую операцию записи, будет блок до завершения первой операции