在虚拟机中为单个线程锁定文件。

16 浏览
0 Comments

在虚拟机中为单个线程锁定文件。

我有多个线程在将我的“Data”对象序列化为文件。

文件名基于对象中的2个字段。

 class Data {

org.joda.DateTime time;

String title;

public String getFilename() {

return time.toString() + \'_\' + title + \".xml\";

}

可能会有2个Data对象具有相同的“time”和“title”,因此具有相同的文件名。

这是可接受的,我很高兴任何一个都可以被保存(如果这些内容相同,则它们可能是相同的Data对象)。

我的问题是两个(或更多)线程同时写入文件,导致XML格式不正确。

我查看了java.nio.channels.FileLock,但它是用于虚拟机范围锁定,不适用于线程内部锁定。

我可以在DataIO.class上进行同步(但这将导致巨大的开销,因为我只想在各个文件上同步)。

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

以下是代码:

 class DataIO {

public void writeArticleToFile(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(\"无法删除文件以进行覆盖写入:\" + file);

}

} else {

throw new IOException(\"文件\" + file + \"已存在,且覆盖标志已设置为false。\");

}

}

File parentFile = file.getParentFile();

if (parentFile != null) {

file.getParentFile().mkdirs();

}

file.createNewFile();

if (!file.canWrite()) {

throw new IOException(\"您无权写入文件:\" + file);

}

FileOutputStream fos = new FileOutputStream(file, false);

try {

writeDataToStream(data, fos);

logger.debug(\"成功将文章写入文件:\" + file.getAbsolutePath());

} finally {

fos.close();

}

}

}

admin 更改状态以发布 2023年5月21日
0
0 Comments

你可以将文件名作为字符串使用intern()函数。然后在这个interned字符串上进行同步。

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);
    }
  }

0
0 Comments

如果我理解正确,您有一个表示单个文件的 Data 对象。

您可以考虑创建一个基于 Data 对象的分段集合。可能有一个 ConcurrentHashMap 的映射关系为

ConcurrentMap lockMap = new ConcurrentHashMap();

当您想写入此对象时,可以执行:

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

请记住,您需要根据标题和日期时间编写 hashCode 和 equals 方法。

0