我正在编写一个类来管理名为 FileLocker 的文件锁定。 由于 java.nio.channels.FileLock ,它的构建方法锁定了一个文件(该目录作为方法的参数被接收)。 FileLocker 类还包含一个release()方法,释放在其buildier方法中创建的FileLock。问题是必须调用release()方法,否则永远不会释放文件的锁定,并且不允许其他进程使用此文件(在此期间)当前的JVM)。 所以我的问题是:是否存在一种方法来指示必须在使用 FileLocker 对象的所有代码中调用release()方法,以便在这些代码编译期间如果没有使用release()方法,则抛出错误? (这里我发布 FileLocker 类代码,只是为了展示它是如何工作的):
package essentialServer_Service;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import essentialServer_Exception.EssentialServerException;
public class FileLocker implements ServerConfiguration{
String fileDirectory;
int filelockingAttempts;
int maxFilelockingAttempts;
FileChannel fileChannel;
RandomAccessFile randomAccessFile;
FileLock lock;
file f;
public FileLocker (String fileDirectory) throws EssentialServerException {
this.fileDirectory = fileDirectory;
filelockingAttempts = 0;
maxFilelockingAttempts = maxDatabaseFilesLockingAttempts();
f = new file(fileDirectory);
f.make(); // To open a channel for a specific file, this file must exist
// Note that the file.make() method throws an EssentialServerException if it seems to be impossible to create the file
fileChannel = null;
randomAccessFile = null;
try{
randomAccessFile = new RandomAccessFile(f, "rw");
fileChannel = randomAccessFile.getChannel();
}catch (FileNotFoundException e){
throw new EssentialServerException(4);
}
lock = null;
while (true) {
try{
lock = fileChannel.tryLock();
}catch (OverlappingFileLockException e){
filelockingAttempts++;
if (filelockingAttempts > maxFilelockingAttempts && maxFilelockingAttempts > -1){
try{
fileChannel.close();
randomAccessFile.close();
}catch (IOException ee){
throw new EssentialServerException(7);
}
throw new EssentialServerException(5);
}
}catch (IOException e) {
filelockingAttempts++;
if (filelockingAttempts > maxFilelockingAttempts && maxFilelockingAttempts > -1){
try{
fileChannel.close();
randomAccessFile.close();
}catch (IOException ee){
throw new EssentialServerException(8);
}
throw new EssentialServerException(6);
}
}
}
}
public void release (int ExceptionType) throws EssentialServerException{
//The int value ExceptionType indicate the EssentialServerException's type that the FileLocker class should throw if the file unlocking fails
try{
lock.release();
fileChannel.close();
randomAccessFile.close();
}catch (IOException ee){
throw new EssentialServerException(ExceptionType);
}
}
}
答案 0 :(得分:1)
直接回答你的问题 - 我不知道直接执行此问题的方法。但是,我想转介您到AutoCloseable
界面。它允许您编写可在try-with-resources代码块中使用的代码。
不知道(真的忽略)代码的所有细节,使用它可能看起来像这样:
try (FileLocker locker = new FileLocker(filename)) {
// Use locker
}
您可以选择添加catch和finally块。但重点是,这可以保证在退出try-block之前锁定器将被“关闭”。
此外,如果FileLocker
只是一个不会在try {}
块中进一步使用的任意对象,除了再次释放它之外,您可以按如下方式简化:
try (new FileLocker(filename)) {
// Your code during FileLocker
}
为了实现这一点,您的FileLocker
必须延长AutoCloseable
。实际上,如果您的FileLocker
会抛出IOException
,您也可以考虑延长Closeable
。您需要实施close
方法,基本上必须调用release
方法。
答案 1 :(得分:0)
在Java中锁定文件非常简单。 FileChannel(Java Doc)提供了锁定文件所需的所有方法。 tryLock()(Java Doc)方法将尝试在不等待的情况下获取文件上的锁。如果获取了锁,则返回FileLock(Java Doc)的实例,否则此方法返回null。
FileLock仅用于进程间锁定,javadoc读取:
"文件锁代表整个Java虚拟机。它们不适合控制同一虚拟机中多个线程对文件的访问。" 要锁定java线程(相同的JVM),您需要使用一些共享锁。我建议在文件编写类中使用synchronized块(根据这些文章可能表现最佳):
另一种方法是使用ReentrantLock:
final ReentrantLock lock = new ReentrantLock();
public void write(...){
try {
lock.lock()
// do the writing
} finally {
// forget this and you're screwed
lock.unlock();
}
}
这种情况使用锁来解决写入的交错,而不是并发访问。进一步的并发锁功能更丰富。但同步锁也可以完成任务。read doc
然而,锁和重入锁都是关闭的要求。所以具有资源功能的新尝试是方便的,它实现了AutoCloseable接口,这是与新的try-with-resource语法一起使用所必需的。所以你可以编写一个简单的包装器,如:
public class LockWrapper implements AutoCloseable
{
private final Lock _lock;
public LockWrapper(Lock l) {
this._lock = l;
}
public void lock() {
this._lock.lock();
}
public void close() {
this._lock.unlock();
}
}
现在您可以编写如下代码:
try (LockWrapper someLock = new LockWrapper(new ReentrantLock()))
{
someLock.lock();
// ...
}