Domanda

Non ho più thread, che sono la serializzazione miei oggetti 'dati' per i file. Il nome del file si basa su 2 campi da oggetto

  class Data {
    org.joda.DateTime time;
    String title;

    public String getFilename() {
      return time.toString() + '_' + title + ".xml";
    }

E 'possibile che 2 oggetti dati avranno lo stesso 'tempo' e 'il titolo', e così lo stesso nome.

Questa è accettabile, e sono felice sia per essere salvati. (Sono probabilmente lo stesso oggetto di dati in ogni caso se questi sono gli stessi)

Il mio problema è che due (o più) le discussioni stanno scrivendo in un file ALLO STESSO TEMPO, causando XML valido.

Ho dato un'occhiata a java.nio.channels.FileLock, ma è per il VM-Wide di chiusura, e in particolare non adatto per blocco intra-Thread.

ho potuto sincronizzare il DataIO.class (ma che causerà una testa enorme, dal momento che in realtà voglio solo sincronizzare sul singolo file).

Sincronizzazione sull'oggetto file sarà inutile, come più oggetti File possono rappresentare lo stesso System-file.

codice segue:

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();
    }
  }
}
È stato utile?

Soluzione

Si potrebbe intern () la stringa che è il nome del file. Quindi sincronizzare sulla corda internati.

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

Altri suggerimenti

Se io sto leggendo correttamente questo si dispone di un oggetto Data che rappresenta un singolo file.

E 'possibile prendere in considerazione la creazione di un set di righe in base all'oggetto dei dati. Possibilmente avente una ConcurrentHashMap di

ConcurrentMap<Data,Lock> lockMap = new ConcurrentHashMap<Data,Lock>();

No quando si desidera scrivere a questo oggetto si può fare:

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

Tenete a mente che avrebbe dovuto scrivere il hashCode e uguale metodo basato sul titolo e DateTime

Sono d'accordo che utilizzando la sincronizzazione è la tecnica si dovrebbe usare. Quello che vi serve è un oggetto distinto per ogni file permutazione, e soprattutto lo stesso oggetto ogni volta. Una possibilità potrebbe essere quella di creare una classe chiamata 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;
            }
        }
    }
}

Poi i chiamanti userebbero come:

synchronized (FileLock.getLock(time, title)) {
    ...
}

Tenete a mente questo è una perdita di memoria in quanto la Hashtable continua a crescere con nuove combinazioni di file / ora. Se è necessario, è possibile modificare questa tecnica in modo che i chiamanti di getLock anche invocare un metodo releaseLock che si utilizza per mantenere il Hashtable pulita.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top