具体来说,我正在寻找的行为是这样的: 读操作同时发生,并将在所有挂起的写操作完成后执行。 写操作始终等待所有其他读/写操作完成。 关闭操作始终等待,直到所有其他读/写操作完成。 换句话说,这些操作应该排队。
NIO FileLocks的官方文档未指定此行为。事实上,它表明:
代表整个Java虚拟机保存文件锁。他们 不适合控制多个线程对文件的访问 在同一个虚拟机中。
在提交新的I / O请求之前,我已经尝试过手动排队所有请求并在所有未完成的期货上调用get() 但我不知道这是不是一个好主意。
我该如何实现这种行为?
编辑:感谢fge的见解,我设法找到了解决问题的基本方法:
import java.nio.file.Path;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ChannelAccessFactory {
public static final ExecutorService IO_THREADS = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private final Path file;
private final ReadWriteLock lock;
public ChannelAccessFactory (Path file){
this.file = file;
this.lock = new ReentrantReadWriteLock();
}
public ReadWriteLock getLock(){
return lock;
}
public ChannelAccess newAccess() throws Exception{
return new ChannelAccess(file, lock);
}
}
Wrapped Channel类:
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReadWriteLock;
public class ChannelAccess implements AutoCloseable{
private final ReadWriteLock lock;
private final AsynchronousFileChannel channel;
protected ChannelAccess (Path file, ReadWriteLock lock) throws Exception{
this.lock = lock;
this.channel = AsynchronousFileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE);
}
public Future<Integer> read(final ByteBuffer buffer, final long position){
return ChannelAccessFactory.IO_THREADS.submit(new Callable<Integer>(){
@Override
public Integer call() throws InterruptedException, ExecutionException{
lock.readLock().lock();
try{
return channel.read(buffer, position).get();
}
finally {
lock.readLock().unlock();
}
}
});
}
public Future<Integer> write(final ByteBuffer buffer, final long position){
return ChannelAccessFactory.IO_THREADS.submit(new Callable<Integer>(){
@Override
public Integer call() throws InterruptedException, ExecutionException {
lock.writeLock().lock();
try{
return channel.write(buffer, position).get();
}
finally {
lock.writeLock().unlock();
}
}
});
}
public long size() throws Exception{
lock.readLock().lock();
try{
return channel.size();
}
finally{
lock.readLock().unlock();
}
}
@Override
public void close() {
lock.readLock().lock();
try{
channel.close();
}
catch (IOException e){}
finally{
lock.readLock().unlock();
}
}
}
答案 0 :(得分:3)
使用ReentrantReadWriteLock
。它允许许多并发读者,但只允许一个作者。
它不是一个“纯粹的”NIO解决方案,但它是一个原始的行为,你的行为方式。
小心:使用这样的锁来避免死锁:
rwlock.readLock().lock();
try {
// do stuff
} finally {
rwlock.readLock().unlock();
}