我有多个线程正在将我的'数据'对象序列化为文件。文件名是基于2场从对象锁定虚拟机中单个线程的文件
class Data { org.joda.DateTime time; String title; public String getFilename() { return time.toString() + '_' + title + ".xml"; }
这可能是2个数据对象将具有相同的“时间”和“标题”,所以相同的文件名。
这是可以接受的,我很高兴能够被保存。 (如果这些数据对象相同,它们可能是相同的数据对象)
我的问题是两个(或更多)线程在同一时间写入文件,从而导致格式错误的XML。
我看了一下java.nio.channels.FileLock,但它是针对VM范围锁定的,并且不适用于线程内部锁定。
我可以在DataIO.class上同步(但这会导致巨大的开销,因为我真的只想在单个文件上同步)。
因为多个File对象可以表示同一个System-File,所以File对象上的同步将无用。
代码如下:
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(); } } }
绝对是最简单的解决方案。不是没有风险,但是因为锁定对象的最佳做法是不可公开访问的。 (和一个interned字符串总是可用的任何地方) – 2010-08-04 15:19:38
这是真实的,很好的做法。但是,您并未锁定字符串本身,更多的是使用该字符串形成DataIO类中锁的基础。查看修改后的帖子 – 2010-08-04 15:30:34
这真的是一个非常整洁的解决方案,但正如柯克沃尔所说,我可能需要在其他地方的字符串(特别是阅读文件等)。但是,如果我在文件名前面添加了一些不寻常的,令人费解的字符串(可能是完全限定的类名),然后锁定THAT字符串的intern(),那么需要精确字符串对象几乎为0的机会几乎是可以接受的对我来说。 – barryred 2010-08-04 15:31:42