我有一个write
方法,可以安全地将数据写入文件。
// The current file I am writing to.
FileOutputStream file = null;
...
// Synchronized version.
private void write(byte[] bytes) {
if (file != null && file.getChannel() != null) {
try {
boolean written = false;
do {
try {
// Lock it!
FileLock lock = file.getChannel().lock();
try {
// Write the bytes.
file.write(bytes);
written = true;
} finally {
// Release the lock.
lock.release();
}
} catch (OverlappingFileLockException ofle) {
try {
// Wait a bit
Thread.sleep(0);
} catch (InterruptedException ex) {
throw new InterruptedIOException("Interrupted waiting for a file lock.");
}
}
} while (!written);
} catch (IOException ex) {
log.warn("Failed to lock " + fileName, ex);
}
} else {
log.warn("Failing - " + (file == null ? "file" : "channel") + " is null!!");
}
}
现在它对我来说已经好了一段时间,虽然我知道它有一些皱纹。
我最近更改了一个使用此代码在Java 5(来自Java 6)下构建和运行的项目,现在看起来它已死锁,等待锁定文件。它是一个多线程应用程序,很多线程很可能尝试写入同一个文件。
调试器告诉我挂起的线程正在等待FileLock lock = file.getChannel().lock()
调用返回。
一些研究提出了这个有趣的小nugget,其中提到:
代表整个Java虚拟机保存文件锁。 它们不适合控制同一虚拟机中多个线程对文件的访问。
我做错了吗?如果是这样,什么是正确的方法?如果我做得对,我怎么会遇到僵局?
已添加:忘记提及 - 每个帖子都拥有自己的此对象副本,因此代码中不应存在任何同步问题。依靠FileChannel.lock()
方法确保写入不会交错,我感到安全。
已添加:我确实使用各种synchronized
机制解决了这个问题。但是,我的问题很突出:
FileLock lock = file.getChannel().lock();
不合适??答案 0 :(得分:3)
FileLock
仅用于进程间锁定,javadoc读取:
“文件锁代表整个Java虚拟机。 它们不适合控制多个文件的访问 同一虚拟机中的线程。“
要锁定java线程(相同的JVM),您需要使用一些共享锁。我建议在文件编写类中使用同步块(according到these articles可能表现最佳):
final Object lock = new Object();
public void write(...){
synchronized(lock){
// do writing
}
}
另一种方法是使用ReentrantLock,然后使用
的成熟惯用法final ReentrantLock lock = new ReentrantLock();
public void write(...){
try {
lock.lock()
// do the writing
} finally {
// forget this and you're screwed
lock.unlock();
}
}
答案 1 :(得分:1)
您可能需要使用文件而不是hashmap在实际代码上实现关键部分概念。您可以创建同步块或将文件访问代码分离到单独的过程中,并使该方法同步。
基本上,一次只有一个线程执行同步块。它为您提供所需的独家访问权限。
另一种方法是使用串行线程Executor,具体取决于您的功能要求。
你可能想看一下这个帖子: Howto synchronize file access in a shared folder using Java (OR: ReadWriteLock on network level)