12
votes

Java: Thread-Safe RandomAccessfile

Après que certains googres sérieux, j'ai découvert que la classe RandomAccessFile n'est pas de sécurité. Maintenant, je pourrais utiliser un sémaphore pour verrouiller toutes les lectures et écrires mais je ne pense pas très bien cela. 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 du tout?

merci!


6 commentaires

Cela dépend de la façon dont vous lisez et écrivez du fichier, mais la synchronisation des primitives de Java.Util.ConCurrent se produisent très bien sur la JVM moderne.


Je comprends si vous essayez d'utiliser le même fichier randomAccess de différents threads, mais vous devez vraiment faire plusieurs lectures simultanément? Je ne suis pas un expert, mais dans la plupart des cas, le matériel ne sera pas en mesure de servir plusieurs lectures en même temps (je ne sais pas pour les tableaux de disques haut de gamme).


Cela fonctionnera avec des matrices de raid. De plus: lorsque les données proviennent du cache, il peut être récupéré en parallèle.


Si les données proviennent du cache, je pense que l'accès est si rapide (par rapport à l'accès au disque) qui ne fait pas beaucoup de différence. Mais si vous avez vraiment besoin de ce type de parallélisme, je suis curieux de votre contexte. Pouvez-vous donner encore plus de détails?


J'ai une table sur le disque (des centaines de gigaoctets) sur lesquels je ressemble et écrit au hasard. Maintenant, je voudrais avoir un fil séparé qui copie les données.


Si je le lisais correctement (j'ai lu la documentation OpenJDK), le nouveau Asynchronousfilechannel (Java 7) également de le faire: "Les canaux de ce type sont sûrs pour une utilisation par plusieurs threads simultanés".


5 Réponses :


7
votes

Je pourrais utiliser un sémaphore pour verrouiller tout lit et écrit mais je ne pense pas cela fonctionne très bien.

En ce qui concerne la performance, ne pensez jamais. Toujours mesurer.

qui dit, java.util.concurrent.lock.reentrantreadritelock est ce que vous recherchez.



3
votes

Le verrouillage partiel d'un fichier est une entreprise complexe qui, beaucoup de systèmes d'exploitation, évitez de faire. Toutefois, si vous insistez sur le faire, une solution est de concevoir votre propre objet de mécanisme de verrouillage qui enregistre les parties du fichier sont verrouillées. Essentiellement avant de lire ou d'écrire un objet doit demander une serrure pour une plage d'octets spécifique du fichier. Les verrous sont considérés comme des affrontements s'ils se chevauchent du tout dans la plage d'octets. Les serrures de lecture et d'écriture sont traitées différemment: une lecture peut se chevaucher avec n'importe quel nombre de serrures de lecture en toute sécurité, mais une serrure d'écriture doit se chevaucher sans autre serrure, lire ou écrire. Il y a beaucoup de questions sur l'attente ou l'abandon si vous ne pouvez pas obtenir le verrou, et s'il faut bloquer les lectures pendant qu'une écriture attend, mais seulement vous pouvez y répondre de votre application.

Compte tenu de la complexité de celle-ci, 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'écriture.


2 commentaires

HMMM idée intéressante. J'ai une liste de lecture (INT NR) et un ELIMEDBLOCK (INT NR). Maintenant, je pourrais avoir un sémaphore de tableau [] Serrures = Nouveau sémaphore [10]; Ensuite, dans ReadBlock / Writeblock (), je pourrais faire des verrous [NR% 10] .acquireUnInterruptimativement () Vous ne pouvez penser à aucun problème avec cela. Alough je pense toujours que le fichier aléatoire sous-jacent échouera avec un accès simultané


Le point de faire un objet de verrouillage consiste à empêcher un accès simultané. Vous devez coder pour que tous les threads doivent obtenir une serrure de l'objet de verrouillage avant d'accéder au fichier et la libérer après leur fin.



2
votes

Considérez cette approche - il permet aux lecteurs illimités et lorsqu'un écrivain veut écrire, il attend que les lecteurs actuels se terminent pour faire son é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;
        }
    }

}


2 commentaires

Ressemble à un java.util.concurrent.lock.reentranTreadreadeAlock? Mais toujours: j'ai besoin d'une façon pour plusieurs lectures et / ou écris pour réussir. Et RandomAccessFile n'autorise pas plusieurs lectures.


Oui, mais randomAccessFile n'autorise pas plusieurs lectures. Je cherche une autre classe le faire.



2
votes

Si un simple mutex sur l'ensemble du fichier va vous donner un goulot d'étranglement de la performance et randomAccessfile n'est pas thread-coffre-fort sans mutex, alors vous devez regarder des alternatives à RandomAccessFile .

Une alternative consiste à mapper le fichier en mémoire sous forme de mappé 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. L'écrivain unique / le verrouillage de plusieurs lecteurs multiples à la granularité de l'ensemble serait facile à mettre en œuvre. Vous pouvez également aller plus loin et mettre en œuvre une lecture et une écriture simultanées de sections non chevauchantes du fichier, mais cela serait plus compliqué.

Je ne serais pas surpris d'entendre que quelqu'un, quelque part a déjà mis en œuvre cela comme une bibliothèque réutilisable.


0 commentaires

0
votes

java.nio.channel.filechannel Est-ce que c'est exactement, c'est-à-dire des lectures simultanées et des écrivies à une seule-filetées.


0 commentaires