J'ai plusieurs threads qui sérialisent mes objets 'Data' dans des fichiers. Le nom de fichier est basé sur 2 champs de l'objetVerrouillage d'un fichier pour un thread individuel dans une machine virtuelle
class Data { org.joda.DateTime time; String title; public String getFilename() { return time.toString() + '_' + title + ".xml"; }
Il est possible que 2 objets de données auront le même « temps » et « titre », et ainsi le même nom.
Ceci est acceptable, et je suis heureux que l'un ou l'autre soit enregistré. (Ils sont probablement le même objet Data de toute façon s'ils sont identiques)
Mon problème est que deux threads (ou plus) écrivent dans un fichier EN MÊME TEMPS, provoquant un XML malformé. J'ai jeté un oeil à java.nio.channels.FileLock, mais c'est pour le verrouillage VM-Wide, et en particulier PAS adapté pour le verrouillage intra-Thread.
Je pourrais synchroniser sur DataIO.class (mais cela entraînera un surcoût énorme, puisque je veux vraiment seulement synchroniser sur le fichier individuel).
La synchronisation sur l'objet Fichier sera inutile, car plusieurs objets Fichier peuvent représenter le même fichier système.
Code suit:
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(); } } }
Certainement la solution la plus simple. Pas sans risque cependant puisqu'il est préférable que les objets que vous verrouillez ne soient pas accessibles au public. (et une chaîne interne est toujours disponible n'importe où) –
Ceci est une bonne et bonne pratique. Cependant, vous ne verrouillez pas la chaîne elle-même, mais plutôt en utilisant la chaîne pour former la base d'un verrou dans votre classe DataIO. Voir le post modifié. –
C'est vraiment une solution très soignée, mais comme Kirk Woll dit que je pourrais avoir besoin de cette chaîne ailleurs (en particulier en lisant les fichiers etc). Cependant, si je préfixe le nom de fichier avec une chaîne inhabituelle et alambiquée (probablement le nom complet de la classe), puis verrouillez le intern() de THAT String, les chances de nécessiter cet objet String deviennent presque 0, ce qui est acceptable pour moi. – barryred