Pregunta

Tengo dos independientes hilos de F1 y F2 (para ser precisos, dos instancias de java.util.concurrente.FutureTask) que se ejecutan en paralelo.

F1 hacer algún tipo de procesamiento y, a continuación, copia el resultado en un archivo XML.Luego, repite estos pasos hasta que haya nada que hacer (muchos archivos XML creados).F2 se ve en la F1 el directorio de salida, y tomar un archivo, analizarlo, y en la ejecución de algunos de procesamiento en él.

Esto funciona bastante bastante bien, excepto que a veces, F2 queda truncada de datos XML desde el archivo.Me refiero a que por que una incompleta XML, donde algunos de nodo XML no están presentes.El problema es que no siempre es reproductible, y los archivos que se truncan no son siempre las mismas.Debido a eso, estoy pensando que mientras la F1 es la escritura de un archivo en el disco, F2 está tratando de leer el mismo archivo.Es por eso que a veces me da este tipo de error.

Mi pregunta:Me pregunto si hay algún mecanismo que bloquea (incluso para la lectura) en el archivo de la F1 actualmente está escribiendo hasta que se haya finalizado completamente para escribir en el disco, por lo F2 no será capaz de leer hasta que el archivo está desbloqueado.O cualquier otra forma de resolver mi problema será bienvenida !

La F1 es escribir en el archivo de esta forma:

try {
    file = new File("some-file.xml");
    FileUtils.writeStringToFile(file, xmlDataAsString);
} catch (IOException ioe) {
    LOGGER.error("Error occurred while storing the XML in a file.", ioe);
}

F2 es leer el archivo de esta forma:

private File getNextFileToMap() {
    File path = getPath(); // Returns the directory where F1 stores the results...
    File[] files = path.listFiles(new FilenameFilter() {
        public boolean accept(File file, String name) {
            return name.toLowerCase().endsWith(".xml");
        }
    });
    if (files.length > 0) {
        return files[0];
    }
    return null;
}

// Somewhere in my main method of F2
...
f = getNextFileToMap();
Node xmlNode = null;
try {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document doc = builder.parse(f);
    if (doc != null) {
        xmlNode = doc.getDocumentElement();
    }
} catch (Exception e) {
    LOGGER.error("Error while getting the XML from the file " + f.getAbsolutePath(), e);
}
¿Fue útil?

Solución

Dado que ya está filtrado de archivos .xml en F2, F1 tienen salida a un archivo .temp, a continuación, cambie su nombre por .xml como paso final. De esa manera, F2 ignorará el archivo F1 está haciendo hasta que F1 es completamente hecho con él.

Otros consejos

¿Has mirado en el java.nio.channels.FileLock API?

Una solución más simple podría ser escribir en un nombre de archivo diferente (por ejemplo foo.tmp) y luego cambiar su nombre (por ejemplo, para foo.xml) cuando esté listo - el cambio de nombre es atómica en la mayoría de los sistemas operativos (dentro de un directorio), de modo que cuando el otro proceso ve el archivo XML que debe ser completa. Esto es probable que sea mucho más simple de bloqueo.

Usar la palabra clave sincronizada en un común objeto, un objeto de archivo que apunta al archivo podría ser el mejor en este caso:

 class MyFileFactory {
     private static HashMap<string,File> files = new HashMap<String,File>();
     public static File get(String name) {
         if (!files.keyExists(name)) {
              files.put(name, new File(name));
         }
         return files.get(name);
     }
 }

 // Another class
 synchronized(File f = MyFileFactory::get("some-file.xml")) {
      // read or write here
 }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top