2010-05-21 8 views
6

Après quelques googleing sérieux, j'ai découvert que la classe RandomAccessFile n'est pas thread-safe. Maintenant, je pourrais utiliser un sémaphore pour verrouiller toutes les lectures et écritures, mais je ne pense pas que cela fonctionne très bien. En théorie, il devrait être possible de faire plusieurs lectures et une écriture à la fois. Comment puis-je faire cela en Java? Est-ce possible?Java: thread-safe RandomAccessFile

Merci!

+0

Cela dépend de la façon dont vous lisez et écrivez à partir du fichier, mais les primitives de synchronisation de java.util.concurrent fonctionnent très bien sur la JVM moderne. –

+0

Je comprends si vous essayez d'utiliser le même RandomAccessFile de threads différents, mais vous avez vraiment besoin de faire plusieurs lectures en même temps? Je ne suis pas un expert mais dans la plupart des cas, le matériel ne pourra pas servir plusieurs lectures en même temps (je ne sais pas pour les baies de disques haut de gamme). –

+0

Cela fonctionnera avec les RAID-Arrays. Aussi: lorsque les données proviennent du cache, elles peuvent être récupérées en parallèle. –

Répondre

1

Le verrouillage partiel d'un fichier est une activité complexe que de nombreux systèmes d'exploitation évitent de faire. Cependant, si vous insistez pour le faire, vous pouvez concevoir votre propre mécanisme de verrouillage qui enregistre quelles parties du fichier sont verrouillées. Essentiellement, avant de lire ou d'écrire un objet, vous devez demander un verrou pour une plage d'octets spécifique du fichier. Les verrous sont considérés comme incompatibles s'ils se chevauchent dans une plage d'octets. Les verrous en lecture et en écriture sont traités différemment: une lecture peut chevaucher en toute sécurité un nombre quelconque de verrous de lecture, mais un verrou d'écriture doit chevaucher aucun autre verrou, lecture ou écriture. Il y a beaucoup de questions sur le fait d'attendre ou d'abandonner si vous ne pouvez pas obtenir le verrou, et si vous voulez bloquer les lectures pendant qu'une écriture est en attente, mais seulement vous pouvez y répondre à propos de votre application.

Compte tenu de la complexité de cela, il peut être préférable de verrouiller le fichier entier. Vérifiez si vous obtenez des performances adéquates - et n'oubliez pas que vous pouvez autoriser plusieurs lectures à la fois, tant qu'il n'y a pas d'écritures.

+0

hmmm idée intéressante. J'ai un readblock (int nr) et un writeblock (int nr). maintenant je pourrais avoir un tableau Semaphore [] locks = new Semaphore [10]; puis dans readblock/writeblock() je pourrais faire des verrous [nr% 10] .acquireUninterruptibly() ne peut pas penser à des problèmes avec cela. Je pense toujours que le RandomAccessFile sous-jacent échouera avec un accès concurrent –

+0

Le but de la création d'un objet de verrouillage est d'empêcher qu'il y ait un accès concurrent. Vous devez coder de sorte que tous les threads doivent obtenir un verrou de l'objet de verrouillage avant d'accéder au fichier, et le relâcher une fois qu'ils sont terminés. – DJClayworth

7

je pouvais utiliser un sémaphores pour verrouiller toutes les lectures et écritures, mais je ne pense pas qui fonctionne très bien.

En ce qui concerne la performance, ne pensez jamais. TOUJOURS mesurer. Cela dit, java.util.concurrent.locks.ReentrantReadWriteLock est ce que vous cherchez.

+1

Oui, mais alors je vais faire 2 lectures simultanées ou plus, RandomAccessFile ne gérera pas cela. Voir: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4193259 (la partie 'évaluation') –

+0

Donc, vous ne pouvez pas utiliser un verrou en lecture, donc vous pouvez aussi utiliser la synchronisation. – EJP

1

Considérez cette approche - elle permet un nombre illimité de lecteurs, et lorsqu'un écrivain veut écrire, il attend que les lecteurs actuels aient fini de faire leur écriture.

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

Ressemble à une implémentation java.util.concurrent.locks.ReentrantReadWriteLock? Mais quand même: j'ai besoin d'un moyen pour que plusieurs lectures et/ou écrites réussissent. Et RandomAccessFile n'autorise pas plusieurs lectures. –

+0

Cela permet plusieurs lectures. Juste pas écrit plusieurs fois. – corsiKa

+0

Oui, mais RandomAccessFile n'autorise pas plusieurs lectures. Je suis à la recherche d'un autre cours. –

1

Si simple mutex sur le fichier entier va vous donner un goulot d'étranglement et RandomAccessFile n'est pas thread-safe sans mutex, alors vous devez chercher des alternatives à RandomAccessFile. Une alternative consiste à mapper le fichier en mémoire sous forme de MappedBuffer et d'utiliser des tranches du tampon pour permettre à différents threads d'accéder au fichier sans interférer les uns avec les autres. Un seul auteur/plusieurs lecteurs verrouillant la granularité de l'ensemble serait facile à mettre en œuvre. Vous pouvez également aller plus loin et mettre en œuvre la lecture et l'écriture simultanées de sections du fichier qui ne se chevauchent pas, mais cela serait plus compliqué.

Je ne serais pas surpris d'apprendre que quelqu'un, quelque part, a déjà implémenté cela comme une bibliothèque réutilisable.

Questions connexes