2010-05-21 17 views
6

Después de un poco de googlear encontré que la clase RandomAccessFile no es segura para subprocesos. Ahora podría usar un semáforo para bloquear todas las lecturas y escrituras, pero no creo que funcione muy bien. En teoría, debería ser posible hacer múltiples lecturas y una escritura a la vez. ¿Cómo puedo hacer esto en Java? ¿Es posible?Java: seguro de subproceso RandomAccessFile

Gracias!

+0

Depende de cómo lea y escriba desde el archivo, pero las primitivas de sincronización de java.util.concurrent funcionan muy bien en la JVM moderna. –

+0

Entiendo si está tratando de usar el mismo RandomAccessFile de diferentes subprocesos, pero ¿realmente necesita hacer varias lecturas al mismo tiempo? No soy un experto, pero en la mayoría de los casos el hardware no podrá leer varias lecturas al mismo tiempo (no sé para las matrices de discos de alta gama). –

+0

Funcionará con matrices RAID. Además: cuando los datos provienen de la memoria caché, se pueden recuperar en paralelo. –

Respuesta

1

El bloqueo parcial de un archivo es un negocio complejo que muchos sistemas operativos evitan. Sin embargo, si insiste en hacerlo, una forma es diseñar su propio objeto de mecanismo de bloqueo que registre qué partes del archivo están bloqueadas. Esencialmente, antes de leer o escribir un objeto, debe solicitar un bloqueo para un rango de bytes específico del archivo. Se considera que las cerraduras chocan si se superponen en absoluto en el rango de bytes. Los bloqueos de lectura y escritura se tratan de manera diferente: una lectura puede superponerse con cualquier cantidad de bloqueos de lectura de forma segura, pero un bloqueo de escritura debe superponerse sin otros bloqueos, leer o escribir. Hay muchas preguntas sobre si esperar o cancelar si no puede obtener el bloqueo y si se bloquean las lecturas mientras espera una escritura, pero solo usted puede responderlas sobre su aplicación.

Dada la complejidad de esto, puede ser mejor bloquear el archivo completo. Compruebe si obtiene un rendimiento adecuado, y no olvide que puede permitir varias lecturas a la vez, siempre que no haya escrituras.

+0

hmmm idea interesante. Tengo un readblock (int nr) y un writeblock (int nr). ahora podría tener una matriz Semaphore [] Locks = new Semaphore [10]; luego en readblock/writeblock() Podría hacer bloqueos [nr% 10] .acquireUninterruptibly() No se me ocurre ningún problema con eso. aunque todavía creo que el RandomAccessFile subyacente fallará con el acceso simultáneo –

+0

El objetivo de crear un objeto de bloqueo es evitar que haya un acceso simultáneo. Debe codificar de modo que todos los hilos tengan que obtener un bloqueo del objeto de bloqueo antes de acceder al archivo, y liberarlo después de que hayan terminado. – DJClayworth

7

que podría utilizar un semáforo para bloquear todos de lectura y escritura, pero no creo que funciona muy bien.

Con respecto al rendimiento, NUNCA piense. SIEMPRE mide

Dicho esto, java.util.concurrent.locks.ReentrantReadWriteLock es lo que estás buscando.

+1

Sí, pero luego haré 2 o más lecturas concurrentes, RandomAccessFile no manejará eso. Ver: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4193259 (la parte de 'evaluación') –

+0

Por lo tanto, no puede usar un bloqueo de lectura, así que también puede usar la sincronización. – EJP

1

Considere este enfoque: permite lectores ilimitados, y cuando un escritor desea escribir, espera que los lectores actuales terminen de escribir.

class readWriteSemaphore() { 
    private Object lock; 
    List<Thread> readers; 
    Thread writer; 

    readWriteSemaphore() { 
     readers = new LinkedList<Thread>(); // Linked list is inefficient for many threads, FYI 
     writer = null; 
    } 

    /** 
    * Returns true if and only if you have acquired a read 
    * maybe use while(!rws.acquireRead(Thread.currentThread())) Thread.sleep(50); // or something 
    */ 
    boolean acquireRead(Thread t) { 
     synchronized(lock) { 
      if(writer == null) { 
       readers.add(t); 
       return true; 
      } 
      return false; // yes this could go outside the synch block... oh well 
     } 
    } 

    void releaseRead(Thread t) { 
     synchronized(lock) { 
      while(readers.remove(t)); // remove this thread completely 
     } 
    } 

    boolean acquireWrite(Thread t) { 
     synchronized(lock) { 
      if(writer == null) return false; 
      writer = t; 
     } 
     while(readers.size() > 0) Thread.sleep(50); // give readers time to finish. 
     //They can't re-enter yet because we set the writer, 
     // if you attempt to acquire a write, future reads will be false until you're done 
     return true; 
    } 

    void releaseWrite(Thread t) { 
     synchronized(lock) { 
      if(t != writer) throw new IllegalArgumentException("Only writer can release itself"); 
      writer = null; 
     } 
    } 

} 
+0

Parece una implementación java.util.concurrent.locks.ReentrantReadWriteLock? Pero aún así: necesito una forma para que múltiples lecturas y/o escrituras tengan éxito. Y RandomAccessFile no permite múltiples lecturas. –

+0

Esto permite múltiples lecturas. Simplemente no múltiples escrituras. – corsiKa

+0

Sí, pero RandomAccessFile no permite múltiples lecturas. Estoy buscando otra clase haciéndolo. –

1

Si un mutex simple en todo el archivo se va a dar un cuello de botella, y RandomAccessFile no es seguro para subprocesos y sin un mutex, entonces usted necesita para buscar alternativas a RandomAccessFile.

Una alternativa es asignar el archivo a la memoria como MappedBuffer y usar sectores del buffer para permitir que diferentes hilos accedan al archivo sin interferir entre ellos. El bloqueo de un solo escritor/lector múltiple en la granularidad del conjunto sería fácil de implementar. También podría ir más allá e implementar la lectura y escritura concurrentes de secciones del archivo que no se superpongan, pero eso sería más complicado.

No me sorprendería escuchar que alguien, en algún lugar ya ha implementado esto como una biblioteca reutilizable.

Cuestiones relacionadas