Вопрос

У меня есть несколько потоков, которые сериализуют мои «данные» объектов для файлов. Имя файла основано на 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top