Ich habe mehrere Threads, die meine 'Data'-Objekte in Dateien serialisieren. Der Dateiname basiert auf 2 Feldern des Objekts
class Data {
org.joda.DateTime time;
String title;
public String getFilename() {
return time.toString() + '\_' + title + ".xml";
}
Es ist möglich, dass 2 Datenobjekte die gleiche "Zeit" und den gleichen "Titel" und damit den gleichen Dateinamen haben.
Das ist akzeptabel, und ich bin froh, wenn einer von beiden gerettet wird. (Wahrscheinlich handelt es sich sowieso um dasselbe Datenobjekt, wenn es dasselbe ist)
Mein Problem ist, dass zwei (oder mehr) Threads in eine Datei GLEICHZEITIG schreiben, was zu fehlerhaftem XML führt.
Ich hatte einen Blick auf java.nio.channels.FileLock, aber es ist für VM-Wide Sperren, und speziell NICHT geeignet für Intra-Thread-Sperren.
Ich könnte auf DataIO.class synchronisieren (aber das wird einen RIESIGEN Overhead verursachen, da ich wirklich nur auf die einzelne Datei synchronisieren möchte).
Eine Synchronisierung mit dem File-Objekt ist nutzlos, da mehrere File-Objekte dieselbe System-Datei darstellen können.
Code Folgt:
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();
}
}
}