2010-05-21 2 views
6

Dopo un po 'di googleing serio ho scoperto che la classe RandomAccessFile non è thread-safe. Ora potrei usare un semaforo per bloccare tutte le letture e le scritture, ma non penso che funzioni molto bene. In teoria dovrebbe essere possibile fare più letture e una scrittura alla volta. Come posso farlo in Java? È possibile a tutti?Java: RandomAccessFile thread-safe

Grazie!

+0

Dipende da come si legge e si scrive dal file, ma le primitive di sincronizzazione da java.util.concurrent si comportano molto bene con la JVM moderna. –

+0

Capisco se si sta tentando di utilizzare lo stesso RandomAccessFile da thread diversi, ma è davvero necessario eseguire più letture contemporaneamente? Non sono un esperto ma nella maggior parte dei casi l'hardware non sarà in grado di servire più letture contemporaneamente (non so per gli array di dischi high-end). –

+0

Funzionerà con gli array RAID. Inoltre: quando i dati provengono dalla cache, possono essere recuperati in parallelo. –

risposta

1

Il blocco parziale di un file è un'attività complessa che molti sistemi operativi non riescono a fare. Tuttavia, se si insiste a farlo, un modo è quello di progettare il proprio oggetto meccanismo di blocco che registra quali parti del file sono bloccate. In sostanza, prima di leggere o scrivere un oggetto è necessario richiedere un blocco per un intervallo di byte specifico del file. I blocchi vengono considerati in conflitto se si sovrappongono del tutto nell'intervallo di byte. I blocchi di lettura e scrittura sono trattati in modo diverso: una lettura può sovrapporsi con qualsiasi numero di blocchi di lettura in modo sicuro, ma un blocco di scrittura deve sovrapporsi senza altri blocchi, leggere o scrivere. Ci sono molte domande su se aspettare o interrompere se non riesci a ottenere il blocco e se bloccare le letture mentre una scrittura è in attesa, ma solo tu puoi rispondere loro della tua applicazione.

Data la complessità di questo potrebbe essere meglio bloccare l'intero file. Controlla se ottieni prestazioni adeguate e non dimenticare che puoi consentire più letture contemporaneamente, a condizione che non ci siano scritture.

+0

hmmm idea interessante. Ho un readblock (int nr) e un writeblock (int nr). ora potrei avere un array Semaphore [] locks = new Semaphore [10]; quindi in readblock/writeblock() potrei fare blocchi [nr% 10] .acquireUninterruptibly() non riesco a pensare ad alcun problema con quello. anche se continuo a pensare che il RandomAccessFile sottostante non riuscirà con l'accesso simultaneo –

+0

Il punto di creazione di un oggetto di blocco è impedire che ci sia mai un accesso concorrente. Devi codificare in modo che tutti i thread debbano ottenere un blocco dall'oggetto di blocco prima di accedere al file e rilasciarlo dopo aver terminato. – DJClayworth

7

ho potuto utilizzare un semaforo per bloccare tutte le di lettura e scrittura, ma non credo che esegue molto bene.

Per quanto riguarda le prestazioni, non pensate MAI. Misura SEMPRE.

Detto questo, java.util.concurrent.locks.ReentrantReadWriteLock è quello che stai cercando.

+1

Sì, ma poi eseguirò 2 o più letture simultanee, RandomAccessFile non lo gestirà. Vedere: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4193259 (la parte "valutazione") –

+0

Quindi non è possibile utilizzare un blocco di lettura, quindi è possibile utilizzare anche la sincronizzazione. – EJP

1

Considera questo approccio - consente un numero illimitato di lettori, e quando uno scrittore vuole scrivere, aspetta che i lettori attuali finiscano di scrivere.

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

Sembra un'implementazione java.util.concurrent.locks.ReentrantReadWriteLock? Ma ancora: ho bisogno di un modo per più letture e/o scritture per avere successo. E RandomAccessFile non consente più letture. –

+0

Ciò consente letture multiple. Solo non più di una scrittura. – corsiKa

+0

Sì, ma RandomAccessFile non consente più letture. Sto cercando qualche altra classe che lo faccia. –

1

Se un semplice mutex sull'intero file sta per darvi un collo di bottiglia, e RandomAccessFile non è thread-safe senza un mutex, allora avete bisogno di cercare alternative per RandomAccessFile.

Un'alternativa consiste nel mappare il file in memoria come MappedBuffer e utilizzare le sezioni del buffer per consentire a diversi thread di accedere al file senza interferire l'uno con l'altro. Un singolo scrittore/blocco di più lettori alla granularità dell'intero sarebbe facile da implementare. Si potrebbe anche andare oltre e implementare la lettura e la scrittura simultanee di sezioni non sovrapposte del file, ma sarebbe più complicato.

Non sarei sorpreso di sentire che qualcuno, da qualche parte, lo ha già implementato come libreria riutilizzabile.