为什么在锁定文件时会发生OverlappingFileLockException?

时间:2012-03-28 11:03:12

标签: java multithreading locking

我尝试锁定文件并使用以下代码写入:

public class TrainSetBuildTask implements Runnable {
    private String pathname;
    public TrainSetBuildTask(String pathname){
        this.pathname = pathname;
    }

    @Override
    public void run() {
          try {
              String content = "content\n";
             //write to a file
             FileOutputStream os = new FileOutputStream(new File(pathname), true);
             FileChannel channel = os.getChannel();
             FileLock lock = channel.tryLock();
             if (lock != null) {
                ByteBuffer bytes = ByteBuffer.wrap(content.getBytes()); 
                channel.write(bytes);
                lock.release();
             }
             channel.close();
             os.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
     }
 }

新的两个线程与类的实例:

    String pathname = "/home/sjtu123/test.arff";
    TrainSetBuildTask task1 = new TrainSetBuildTask(pathname);
    Thread t1 = new Thread(task1);
    TrainSetBuildTask task2 = new TrainSetBuildTask(pathname);
    Thread t2 = new Thread(task2);
    t1.start();
    t2.start();

然后我得到错误OverlappingFileLockException。我想知道为什么会发生这种情况因为我只是在每个线程中锁定一次文件?如何修复我的代码?

2 个答案:

答案 0 :(得分:2)

文件全局锁定,而不仅仅是每个线程或每个进程。

你需要按顺序运行你的两个线程:

String pathname = "/home/sjtu123/test.arff";
TrainSetBuildTask task1 = new TrainSetBuildTask(pathname);
Thread t1 = new Thread(task1);
TrainSetBuildTask task2 = new TrainSetBuildTask(pathname);
Thread t2 = new Thread(task2);
t1.start();
t1.join(); // Wait for t1 to die.
t2.start();

评论后的新版本:

FileWriter pathname = new FileWriter("/home/sjtu123/test.arff");
TrainSetBuildTask task1 = new TrainSetBuildTask(pathname);
Thread t1 = new Thread(task1);
TrainSetBuildTask task2 = new TrainSetBuildTask(pathname);
Thread t2 = new Thread(task2);
t1.start();
t2.start();
t1.join();
j2.join();
synchronized (pathname){
    pathname.close();
}

public class TrainSetBuildTask implements Runnable {
    private FileWriter pathname;
    public TrainSetBuildTask(FileWriter pathname){
        this.pathname = pathname;
    }

    @Override
    public void run() {
          try {
             // Do work
             synchronized (pathname){
             // Write to file
             }
          } catch (IOException e) {
              e.printStackTrace();
          }
     }
 }

答案 1 :(得分:2)

您无法同时多次锁定同一文件。您需要使用java锁定对象来确保一次只有一个线程尝试锁定文件,或者协调线程以等待其他线程没有锁定。

来自manual

  

代表整个Java虚拟机保存文件锁。它们不适合控制同一虚拟机中多个线程对文件的访问。