2012-03-28 185 views
2

我试图锁定一个文件,并写入它与下面的代码:锁定一个文件时,为什么会发生OverlappingFileLockException?

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

不能锁定相同的文件超过一次同时。要么需要使用java锁对象来确保一次只有一个线程试图锁定文件,要么协调这些线程以等待,直到没有其他线程被锁定。

manual

文件持有锁代表了整个Java虚拟机。它们不适用于控制同一虚拟机内多个线程对文件的访问。

+0

那么'FileLock'的用法是什么,因为它不能用于协调想要写入文件的线程? @Atila – 2012-03-28 11:30:52

+0

这是为了防止其他人(例如其他程序)与持有该锁的人同时访问该文件。该异常指示别人(在这种情况下你自己的一个线程)已经在文件上的锁。如果你不想放弃(从你的程序的角度来看),你可以稍后尝试,例如,希望到那时锁定被释放。 – Attila 2012-03-28 11:34:47

+0

我在上面写这些代码之前已经阅读了手册,并且不理解它们的含义。现在我明白了,谢谢。 @Attila – 2012-03-28 11:44:08

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(); 
      } 
    } 
} 
+0

我希望T2可以做一些工作,除了写入文件。但是你的代码意味着线程T2可以开始只工作线程T1已完成其工作后,不管不管T2是否愿意写这是由T1锁定了文件。 @Johannes – 2012-03-28 11:26:09

+0

这是不完全清楚的问题,而是看看在新的版本而不是呢。它可能不是100%正确的,但你应该得到一般想法。 – Johannes 2012-03-28 11:37:31

相关问题