studio sincronizacion resueltos programacion móviles leer hilos fuente ejemplos desarrollo curso con codigo archivos aplicaciones java multithreading file-io synchronization

sincronizacion - runnable java



Java: cómo sincronizar la modificación de archivos por hilos (2)

Aquí hay una sugerencia ligeramente diferente. Asumiendo que los nombres de tus archivos no tienen caracteres ''/ n'' en ellos (es una gran suposición en Linux, lo sé, pero puedes hacer que tu escritor busque eso), ¿por qué no solo leer líneas completas e ignorar las incompletas? Por líneas incompletas, quiero decir líneas que terminan con EOF y no con / n.

Editar: vea más sugerencias en los comentarios a continuación.

Solo se puede ejecutar una instancia de mi aplicación Java a la vez. Se ejecuta en Linux. Necesito asegurarme de que un hilo no modifique el archivo mientras el otro hilo lo está usando.

No sé qué método de sincronización o bloqueo de archivos usar. Nunca he hecho bloqueo de archivos en Java y no tengo mucha experiencia en Java o programación.

Miré en java NIO y leí que "Los bloqueos de archivos se realizan en nombre de toda la máquina virtual Java. No son adecuados para controlar el acceso a un archivo por varios subprocesos dentro de la misma máquina virtual". Inmediatamente supe que necesitaba la ayuda de un experto porque este es el código de producción y casi no tengo idea de lo que estoy haciendo (y tengo que hacerlo hoy).

Aquí hay un breve resumen de mi código para cargar algunas cosas (archivos) a un servidor. Obtiene la lista de archivos para cargar desde un archivo (llámalo "listFile") - y listFile se puede modificar mientras este método está leyendo desde allí. Minimizo las posibilidades de eso al copiar listFile a un archivo temporal y usar ese archivo temporal a partir de entonces. Pero creo que necesito bloquear el archivo durante este proceso de copia (o algo así).

package myPackage; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import com.example.my.FileHelper; import com.example.my.Logger; public class BatchUploader implements Runnable { private int processUploads() { File myFileToUpload; File copyOfListFile = null; try { copyOfListFile = new File("/path/to/temp/workfile"); File origFile = new File("/path/to/listFile"); //"listFile" - the file that contains a list of files to upload DataWriter.copyFile(origFile, copyOfListFile);//see code below } catch (IOException ex) { Logger.log(ex); } try { BufferedReader input = new BufferedReader(new FileReader(copyOfListFile)); try { while (!stopRunning && (fileToUploadName = input.readLine()) != null) { upload(new File(fileToUploadName)); } } finally { input.close(); isUploading = false; } } return filesUploadedCount; } }

Aquí está el código que modifica la lista de archivos que se cargarán utilizados en el código anterior:

public class DataWriter { public void modifyListOfFilesToUpload(String uploadedFilename) { StringBuilder content = new StringBuilder(); try { File listOfFiles = new File("/path/to/listFile"); //file that contains a list of files to upload if (!listOfFiles.exists()) { //some code } BufferedReader input = new BufferedReader(new FileReader(listOfFiles)); try { String line = ""; while ((line = input.readLine()) != null) { if (!line.isEmpty() && line.endsWith(FILE_EXTENSION)) { if (!line.contains(uploadedFilename)) { content.append(String.format("%1$s%n", line)); } else { //some code } } else { //some code } } } finally { input.close(); } this.write("/path/to/", "listFile", content.toString(), false, false, false); } catch (IOException ex) { Logger.debug("Error reading/writing uploads logfile: " + ex.getMessage()); } } public static void copyFile(File in, File out) throws IOException { FileChannel inChannel = new FileInputStream(in).getChannel(); FileChannel outChannel = new FileOutputStream(out).getChannel(); try { inChannel.transferTo(0, inChannel.size(), outChannel); } catch (IOException e) { throw e; } finally { if (inChannel != null) { inChannel.close(); } if (outChannel != null) { outChannel.close(); } } } private void write(String path, String fileName, String data, boolean append, boolean addNewLine, boolean doLog) { try { File file = FileHelper.getFile(fileName, path); BufferedWriter bw = new BufferedWriter(new FileWriter(file, append)); bw.write(data); if (addNewLine) { bw.newLine(); } bw.flush(); bw.close(); if (doLog) { Logger.debug(String.format("Wrote %1$s%2$s", path, fileName)); } } catch (java.lang.Exception ex) { Logger.log(ex); } } }


Mi sugiero un enfoque ligeramente diferente. Afair en Linux, la operación de cambio de nombre de archivo (mv) es atómica en los discos locales. No hay posibilidad de que un proceso vea un archivo "medio escrito".

Deje que XXX sea un número de secuencia con tres (o más) dígitos. Puede dejar que su DataWriter se anexe a un archivo llamado listFile-XXX.prepare y escriba un número fijo N de nombres de archivo en él. Cuando se escriben N nombres, cierre el archivo y cámbiele el nombre (atómico, vea arriba) a listFile-XXX. Con el siguiente nombre de archivo, comience a escribir en listFile-YYY donde YYY = XXX + 1.

Su BatchUploader puede verificar en cualquier momento si encuentra archivos que coincidan con el patrón listFile-XXX, abrirlos, leerlos cargar los archivos nombrados, cerrarlos y eliminarlos. No hay posibilidad de que los hilos estropeen el archivo del otro.

Indicaciones de implementación:

  1. Asegúrese de utilizar un mecanismo de sondeo en BatchUploader que espere 1 o más segundos si no encuentra un archivo listo para cargar (evitar la espera inactiva).
  2. Es posible que desee asegurarse de ordenar el listFile-XXX según XXX para asegurarse de que la carga se realice en secuencia.
  3. Por supuesto, puede variar el protocolo de cuando listFile-XXX.prepare está cerrado. Si DataWriter no tiene nada que hacer durante un tiempo más prolongado, no querrá tener archivos listos para cargar, simplemente porque aún no hay N listos.

Beneficios: sin bloqueo (lo que será un dolor hacer bien), sin copia, fácil descripción de la cola de trabajo y estado en el sistema de archivos.