В следующем примере у меня есть один файл, который используется двумя потоками (в реальном примере у меня может быть любое количество потоков)
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class A {
static volatile boolean running = true;
public static void main(String[] args) throws IOException, InterruptedException {
String name = "delete.me";
new File(name).deleteOnExit();
RandomAccessFile raf = new RandomAccessFile(name, "rw");
FileChannel fc = raf.getChannel();
Thread monitor = new Thread(() -> {
try {
while (running) {
System.out.println(name + " is " + (fc.size() >> 10) + " KB");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Interrupted");
Thread.currentThread().interrupt();
}
}
} catch (IOException e) {
System.err.println("Monitor thread died");
e.printStackTrace();
}
});
monitor.setDaemon(true);
monitor.start();
Thread writer = new Thread(() -> {
ByteBuffer bb = ByteBuffer.allocateDirect(32);
try {
while (running) {
bb.position(0).limit(32);
fc.write(bb);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("Interrupted");
Thread.currentThread().interrupt();
}
}
} catch (IOException e) {
System.err.println("Writer thread died");
e.printStackTrace();
}
});
writer.setDaemon(true);
writer.start();
Thread.sleep(5000);
monitor.interrupt();
Thread.sleep(2000);
running = false;
raf.close();
}
}
Скорее создавая RandomAccessFile и сопоставление памяти для каждого потока, у меня есть один файл и одно сопоставление памяти, разделяемое между потоками, но есть catch, если какой-либо поток прерывается, ресурс закрывается.
delete.me is 0 KB
delete.me is 2 KB
delete.me is 4 KB
delete.me is 6 KB
delete.me is 8 KB
Interrupted
Monitor thread died
java.nio.channels.ClosedByInterruptException
at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:202)
at sun.nio.ch.FileChannelImpl.size(FileChannelImpl.java:315)
at A.lambda$main$0(A.java:19)
at java.lang.Thread.run(Thread.java:748)
Writer thread died
java.nio.channels.ClosedChannelException
at sun.nio.ch.FileChannelImpl.ensureOpen(FileChannelImpl.java:110)
at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:199)
at A.lambda$main$1(A.java:41)
at java.lang.Thread.run(Thread.java:748)
Есть ли способ предотвратить блокировку FileChannel только потому, что один поток, использующий его, был прерван?
EDIT Что я хочу избежать, так это, как я подозреваю, это не сработает для Java 9+
private void doNotCloseOnInterrupt(FileChannel fc) {
try {
Field field = AbstractInterruptibleChannel.class
.getDeclaredField("interruptor");
field.setAccessible(true);
field.set(fc, (Interruptible) thread
-> Jvm.warn().on(getClass(), fc + " not closed on interrupt"));
} catch (Exception e) {
Jvm.warn().on(getClass(), "Couldn't disable close on interrupt", e);
}
}
BTW Вызов fc.size()
возвращает размер, как ожидалось, с помощью вышеупомянутого взлома.