Ist eine Lesesperre auf einem ReentrantReadWriteLock ausreichend für die gleichzeitige Lesen eines Random
-
22-09-2019 - |
Frage
Ich bin etwas zu schreiben, die gleichzeitigen Lese- / Schreibanforderungen an eine Datenbank-Datei zu bearbeiten.
ReentrantReadWriteLock sieht aus wie ein gutes Spiel. Wenn alle Threads Zugriff auf ein gemeinsames Random Objekt , muss ich Sorge um die Dateizeiger bei gleichzeitiger Leser? Betrachten Sie folgendes Beispiel:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Database {
private static final int RECORD_SIZE = 50;
private static Database instance = null;
private ReentrantReadWriteLock lock;
private RandomAccessFile database;
private Database() {
lock = new ReentrantReadWriteLock();
try {
database = new RandomAccessFile("foo.db", "rwd");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
};
public static synchronized Database getInstance() {
if(instance == null) {
instance = new Database();
}
return instance;
}
public byte[] getRecord(int n) {
byte[] data = new byte[RECORD_SIZE];
try {
// Begin critical section
lock.readLock().lock();
database.seek(RECORD_SIZE*n);
database.readFully(data);
lock.readLock().unlock();
// End critical section
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
}
In der GetRecord () Methode ist die folgende Verschachtelung möglich mit mehreren gleichzeitigen Lesern?
Thread 1 -> GetRecord (0)
Gewinde 2 -> GetRecord (1)
Thema 1 -> erwirbt gemeinsame Sperre
Thread 2 -> erwirbt gemeinsame Sperre
Thema 1 -> sucht 0
aufnehmen Thread 2 -> sucht 1 | aufzeichnen Thema 1 -> liest Datensatz bei Dateizeiger (1)
Fädeln 2 -> liest Datensatz bei Dateizeiger (1)
Wenn es tatsächlich mögliche Parallelitätsprobleme mit ReentrantReadWriteLock und Random, was wäre eine Alternative?
Lösung
Ja, dieser Code nicht richtig synchronisiert, so wie Sie skizzieren. Eine Lese-Schreibsperre ist nicht sinnvoll, wenn die Schreibsperre nie erworben wird; es ist, als ob es keine Sperre ist.
Mit einem traditionellen synchronized
Block der Such- und Lese erscheinen Atom zu anderen Threads, oder erstellen Sie einen Pool von RandomAccessFile
Instanzen zu machen, die für die ausschließliche Verwendung von einem einzigen Thread entlehnt sind und dann zurückgegeben. (Oder einfach widmen einen Kanal zu jedem Thread, wenn Sie zu nicht viele Threads haben.)
Andere Tipps
Dies ist ein Beispielprogramm, das Sperrdatei und Unlock-Datei.
try { // Get a file channel for the file
File file = new File("filename");
FileChannel channel = new RandomAccessFile(file, "rw").getChannel(); // Use the file channel to create a lock on the file.
// This method blocks until it can retrieve the lock.
FileLock lock = channel.lock(); // Try acquiring the lock without blocking. This method returns // null or throws an exception if the file is already locked.
try {
lock = channel.tryLock();
} catch (OverlappingFileLockException e){}
lock.release(); // Close the file
channel.close();
}
catch (Exception e) { }
Sie können wollen Schlösser mit File System betrachten, anstatt Ihre eigene Verriegelung der Verwaltung.
Anruf getChannel().lock()
auf Random die Datei über die FileChannel
Klasse zu sperren. Dies verhindert, dass der Schreibzugriff, auch von Prozessen außerhalb Ihrer Kontrolle.
Vielmehr arbeitet auf dem einzelnen Sperrobjekt eher als das Verfahren, ReentrantReadWriteLock kann bis zu einem Maximum von 65.535 rekursiven Schreibsperren unterstützen und 65.535 Lesesperren.
Assign eine Lese- und Schreibsperre
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
Dann Arbeit auf sie ...
Sie auch: Sie sind Catering nicht für eine Ausnahme und Versagen zu entsperren im Anschluss an verriegeln. Rufen Sie das Schloss, wie Sie das Verfahren (wie ein Mutex Schließfach), dann tun Sie Ihre Arbeit in einem try / catch-Block mit dem Unlock in dem schließlich Abschnitt eingeben, zB:
public String[] allKeys() {
r.lock();
try { return m.keySet().toArray(); }
finally { r.unlock(); }
}
OK, beträgt 8,5 Jahre sind eine lange Zeit, aber ich hoffe, es ist nicht necro ...
Mein Problem war, dass wir Zugang Ströme benötigen wie möglich zu lesen und zu schreiben als Atom. Ein wichtiger Teil war, dass unser Code sollte auf mehreren Rechnern laufen die gleiche Datei zugreifen. Allerdings sind alle Beispiele im Internet gestoppt zu erklären, wie ein RandomAccessFile
zu sperren und nicht tiefer ging. Also mein Ausgangspunkt war Sams Antwort .
Nun, aus der Ferne macht es Sinn, eine gewisse Ordnung zu haben:
- sperrt die Datei
- Öffnen Sie die Ströme
- tun, was mit den Strömen
- schließen die Ströme
- die Sperre
Um jedoch zu ermöglichen, das Schloss in Java Freigabe die Ströme müssen nicht geschlossen werden! Aufgrund der, dass der gesamte Mechanismus wird ein wenig seltsam (und falsch?).
Um die automatische Schließung der Arbeit zu machen muß bedenken, dass JVM die Entitäten in der umgekehrten Reihenfolge des Try-Segments geschlossen wird. Dies bedeutet, dass ein Fluss sieht wie folgt aus:
- Öffnen Sie die Ströme
- sperrt die Datei
- tun, was mit den Strömen
- die Sperre
- schließen die Ströme
zeigten Tests, dass dies nicht funktioniert. Daher automatische Schließen auf halben Weg und macht den Rest in good ol‘Java 1 Art und Weise:
try (RandomAccessFile raf = new RandomAccessFile(filename, "rwd");
FileChannel channel = raf.getChannel()) {
FileLock lock = channel.lock();
FileInputStream in = new FileInputStream(raf.getFD());
FileOutputStream out = new FileOutputStream(raf.getFD());
// do all reading
...
// that moved the pointer in the channel to somewhere in the file,
// therefore reposition it to the beginning:
channel.position(0);
// as the new content might be shorter it's a requirement to do this, too:
channel.truncate(0);
// do all writing
...
out.flush();
lock.release();
in.close();
out.close();
}
Beachten Sie, dass die Methoden, diese verwenden, müssen noch synchronized
sein. Ansonsten sind die parallelen Ausführungen kann eine OverlappingFileLockException
werfen, wenn lock()
aufrufen.
Bitte teilen Erfahrungen haben, falls Sie eine ...