Блокировка файла для индивидуальной резьбы в VM
-
25-09-2019 - |
Вопрос
У меня есть несколько потоков, которые сериализуют мои «данные» объектов для файлов. Имя файла основано на 2 поля от объекта
данные классов {org.joda.dateTime time; Заголовок строки; Public String GetFileName () {Time.toString () + '_' + заголовок + ".xml"; }
Возможно, что 2 объекта данных будут иметь такое же «время» и «название», и поэтому одинаковое имя файла.
Это приемлемо, и я рад, что либо быть сохраненным. (Они, вероятно, один и тот же объект данных в любом случае, если они одинаковы)
Моя проблема заключается в том, что две (или более) потоки записывают в файл одновременно, вызывая уродливой XML.
Я посмотрел на java.nio.channels.filelock, но это для блокировки VM-шириной, а также специально не подходит для блокировки внутри нити.
Я мог бы синхронизировать на dataio.class (но это приведет к огромному надлому, так как я действительно хочу только синхронизировать в отдельном файле).
Синхронизация на объекте файла будет бесполезным, так как несколько файловых объектов могут представлять один и тот же системный файл.
Следующая код:
Class Dataio {Public Void Woid WidearticletOfile (статья статьи, строковое имя файла, булево перезаписать) бросает ioException {file file = новый файл (имя файла); WritearticletOfile (статья, файл, перезапись); } Общественный void aperiteatoFile (данные данных, файл файла, булева перезаписи) бросает ioException {если (file.exists ()) {если (overrite) {если (! file.delete ()) {бросить новый ioexception ("не удалось удалить Файл для перезаписи: «+ файл); }} else {бросить новый ioException ("файл" + файл + "уже существует, а флаг перезаписи установлен на false"); }} Файл ParentFile = File.getParentFile (); if (parentfile! = null) {file.getparentfile (). mkdirs (); } file.createNewFile (); if (! file.canwrite ()) {бросить новый IOException («У вас нет разрешения на запись в файл:« + файл); } FileOutputStream FOS = новый файлутпутатьStream (файл, ложь); попробуйте {писалatoStream (данные, FOS); logger.debug ("успешно писал статью в файл:" + file.getabsolutepath ()); } Наконец {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 и равен методу, основанным на заголовке и дате времени
Я согласен, что использование синхронизации - это методика, которую вы должны использовать. То, что вам нужно, - это отдельный объект для каждой перестановки файлов и, что более важно того же объекта каждый раз. Один вариант может быть создать класс под названием 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)) {
...
}
Имейте в виду, что это утечка памяти, поскольку Hashtable продолжает расти с новыми перестановками файлов / во времени. Если вам нужно, вы можете изменить эту технику, чтобы абоненты GOBLOCK также вызывают метод ReleaseLock, который вы используете, чтобы сохранить Hashtable Clean.