锁定文件的虚拟机中的单个线程
-
25-09-2019 - |
题
我具有被序列化我的“数据”对象文件的多个线程。文件名是基于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
不隶属于 StackOverflow