Pergunta

Eu tenho dois segmentos independentes F1 e F2 (para ser mais preciso, duas instâncias de java.util.concurrent.FutureTask) que estão sendo executados em paralelo.

F1 fazer algum processamento, e depois copiar o resultado em um arquivo XML. Em seguida, ele repete estes passos até que ele não tem nada para fazer (muitos arquivos XML são criados). F2 olha no diretório de saída F1, e ter um arquivo, analisá-lo e executar algum processamento sobre ele.

Isso funciona muito muito bem, exceto que os dados XML às vezes, F2 fica truncado a partir do arquivo. Quero dizer por que um XML incompleta, onde alguns nó XML não estão presentes. O problema é que nem sempre é reprodutível, e os arquivos que são truncadas nem sempre são os mesmos. Por causa disso, eu estou pensando que, enquanto F1 está escrevendo um arquivo no disco, F2 está tentando ler o mesmo arquivo. É por isso que às vezes eu tenho esse tipo de erro.

A minha pergunta : Eu estou querendo saber se existe algum mecanismo que os bloqueios (mesmo para ler) o F1 arquivo está atualmente escrevendo até que tenha terminado completamente a escrevê-lo no disco, então F2 não vai ser capaz de lê-lo até que o arquivo é desbloqueado. Ou qualquer outra forma de resolver o meu problema será bem-vindo!

F1 está escrevendo o arquivo da seguinte maneira:

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 está lendo o arquivo da seguinte maneira:

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);
}
Foi útil?

Solução

Uma vez que você já está filtrando para arquivos .xml em F2, têm F1 saída para um arquivo .temp, em seguida, renomeá-lo para .xml como um passo final. Dessa forma, F2 irá ignorar a F1 arquivo está fazendo até que F1 é completamente feito com ele.

Outras dicas

Você já olhou para o java.nio.channels.FileLock API?

Uma solução mais simples pode muito bem ser a gravação para um nome diferente (por exemplo foo.tmp) e renomeá-lo (por exemplo, para foo.xml) quando estiver pronto - a renomeação é atômica na maioria dos sistemas operacionais (dentro de um diretório), por isso, quando o outro processo vê o arquivo XML deve ser completa. Este é provável que seja muito mais simples do bloqueio.

Use a palavra-chave sincronizada em comum objeto, um apontando para o arquivo objeto de arquivo seria o melhor neste 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top