我具有被序列化我的“数据”对象文件的多个线程。文件名是基于2个字段从对象

  class Data {
    org.joda.DateTime time;
    String title;

    public String getFilename() {
      return time.toString() + '_' + title + ".xml";
    }

可能的是,2的数据对象将具有相同的“时间”和“标题”,所以相同的文件名。

这是可以接受的,我很高兴要么被保存。 (他们可能是相同的数据对象无论如何,如果这些是相同的)

我的问题是两个(或多个)线程写入文件AT的同时,导致异常的XML。

我有一看java.nio.channels.FileLock中,但它是VM-宽锁定,并且特别是不适合于帧内螺纹锁固。

我可以在DataIO.class同步(但将造成巨大的开销,因为我真的只想对单个文件进行同步)。

同步文件对象上将是无用的,因为多个文件的对象可以表示相同的系统文件。

代码如下:

class DataIO {
  public void writeArticleToFile(Article article, String filename, boolean overwrite) throws IOException {
    File file = new File(filename);
    writeArticleToFile(article, file, overwrite);
  }

  public void writeDataToFile(Data data, File file, boolean overwrite) throws IOException {
    if (file.exists()) {
      if (overwrite) {
        if (!file.delete()) {
          throw new IOException("Failed to delete the file, for overwriting: " + file);
        }
      } else {
        throw new IOException("File " + file + " already exists, and overwrite flag is set to false.");
      }
    }

    File parentFile = file.getParentFile();
    if (parentFile != null) {
      file.getParentFile().mkdirs();
    }

    file.createNewFile();

    if (!file.canWrite()) {
      throw new IOException("You do not have permission to write to the file: " + file);
    }

    FileOutputStream fos = new FileOutputStream(file, false);
    try {
      writeDataToStream(data, fos);
      logger.debug("Successfully wrote Article to file: " + file.getAbsolutePath());
    } finally {
      fos.close();
    }
  }
}
有帮助吗?

解决方案

您可能实习生(),其是文件名的字符串。然后在实习串同步。

class DataIO {
  public void writeArticleToFile(Article article, String filename, boolean overwrite) throws IOException {
    synchronized(filename.intern()) {
       File file = new File(filename);
       writeArticleToFile(article, file, overwrite);
    }
  }

其他提示

如果我正确地读这一点,你有一个代表单个文件的数据对象。

您可以考虑创建基于数据对象上的条纹集。可能具有的ConcurrentHashMap的

ConcurrentMap<Data,Lock> lockMap = new ConcurrentHashMap<Data,Lock>();

没有当你想要写这个对象,你可以这样做:

Lock lock = lockMap.get(someMyDataObject);
lock.lock();
try{
   //write object here
}finally{
   lock.unlock();
}

请记住,你将不得不写的hashCode和equals基于标题方法和DateTime

我同意在使用同步是应该使用该技术。你需要的是对每个文件排列每次不同的对象,更重要的是同一个对象。一个选择是创建一个名为的FileLock类:

public class FileLock {
    DateTime time;
    String title;

    public FileLock(DateTime time, String title) {
        this.time = time;
        this.title = title;
    }

    override equals/hashCode based on those two properties

    static Hashtable<FileLock, FileLock> unqiueLocks = new Hashtable<FileLock, FileLock>();
    static lockObject = new Object();

    public static FileLock getLock(DateTime time, String title) {
        synchronized (lockObject) {
            FileLock lock = new FileLock(time, title);
            if (unqiueLocks.ContainsKey(lock)) {
                return unqiueLocks.get(lock);
            }
            else {
                unqiueLocks.put(lock, lock);
                return lock;
            }
        }
    }
}

然后呼叫者将使用它像:

synchronized (FileLock.getLock(time, title)) {
    ...
}

请记住这有内存泄漏,因为哈希表保持与新的文件/时间排列生长。如果需要,你可以修改该技术,因此GETLOCK的呼叫者也调用RELEASELOCK方法,你用它来保持清洁的Hashtable

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top