Ich arbeite an einer App, die auf eine SQLite-Datenbank zugreift. Das Problem ist, dass die DB gesperrt wird, wenn eine Anfrage an sie vorliegt. Meistens ist das kein Problem, weil der Fluss der App ziemlich linear ist.
Allerdings habe ich einen sehr langen Berechnungsvorgang, der vom Benutzer ausgelöst wird. Dieser Prozess umfasst mehrere Aufrufe an die Datenbank zwischen Berechnungen.
Ich wollte, dass der Benutzer ein visuelles Feedback erhält, also habe ich den javafx progress indicator und einen Service aus dem Framework Javafx.Concurrency verwendet. Das Problem besteht darin, dass der Benutzer sich frei in der App bewegen und möglicherweise andere Aufrufe an die Datenbank auslösen kann.
Dies verursachte eine Ausnahme, dass die Datenbankdatei gesperrt ist. Ich möchte einen Weg finden, diesen Thread zu stoppen, wenn dieser Fall auftritt, aber ich konnte keine klaren Beispiele online finden. Die meisten von ihnen sind zu stark vereinfacht und ich möchte einen Weg, der skalierbar ist. Ich habe versucht, die Methode cancel () zu verwenden, aber das garantiert nicht, dass der Thread rechtzeitig abgebrochen wird.
Da ich nicht in der Lage bin, alle Teile des Codes für isCancelled einzuchecken, gibt es manchmal eine Verzögerung zwischen dem Zeitpunkt, an dem der Thread abgebrochen wird, und der Zeit, zu der er effektiv gestoppt wird.
Also dachte ich über die folgende Lösung nach, aber ich würde gerne wissen, ob es einen besseren Weg in Bezug auf Effizienz und Vermeidung von Rennbedingungen und Hängen gibt.
%Vor%Dies ist meine Serviceklasse, die ich unterklassifiziert habe, um Methoden einzuschließen, die verwendet werden können, um den Status des Dienstes (gestoppt oder nicht gestoppt) festzulegen
%Vor%Der Dienst implementiert diese Schnittstelle, die ich definiert habe
%Vor%Alle Dienste müssen sich beim Thread-Manager registrieren, der eine Singleton-Klasse ist.
%Vor%An jeder Stelle in der App, wenn wir den Dienst stoppen wollen, rufen wir cancelServices () auf. Dadurch wird der Status auf abgebrochen gesetzt. Ich überprüfe dies in meinem calculationMethod () und setze den Status auf kurz vor dem Zurücksetzen (um den Thread zu beenden).
%Vor%(Ich gehe davon aus, dass Sie JDBC für Ihre Datenbankabfragen verwenden und dass Sie die Kontrolle über den Code haben, der die Abfragen ausführt)
Ich würde alle Datenbankzugriffe in einer Singleton-Klasse zentralisieren, wodurch der letzte PreparedStatement
die aktuelle Abfrage in einem einzigen Thread ausführen würde. ExecutorService
. Sie könnten dann diese Singleton-Instanz wie isQueryRunning()
, runQuery()
, cancelQuery()
fragen, die synchronized
wäre, so dass Sie entscheiden können, dem Benutzer eine Nachricht anzuzeigen, wann immer die Berechnung abgebrochen werden sollte, abbrechen und eine neue starten eins.
Etwas wie (fügen Sie Null-Checks und catch (SQLException e)
Blöcke hinzu):
Eine Lösung für Ihr Problem könnte Thead.stop()
sein, was vor Jahrhunderten veraltet war (mehr zum Thema hier ).
Um das ähnliche Verhalten zu implementieren, wird empfohlen, das Thread.interrupt()
zu verwenden, was (im Kontext von Task
) dasselbe ist wie das Task.cancel()
.
Lösungen:
calculationMethod
mit isCancelled()
checks. Thread
zu unterbrechen. Die zweite Lösung ist wahrscheinlich, was Sie suchen, aber es hängt vom tatsächlichen Code von calculationMethod
ab (was ich denke, dass Sie nicht teilen können).
Generische Beispiele zum Beenden langer Datenbankoperationen (all dies wird von einem anderen Thread ausgeführt):
kill <SPID>
). BEARBEITEN:
Ich habe nicht gesehen, dass Sie die Datenbank für SQLite angegeben haben, als ich meine Antwort geschrieben habe. Also, um die Lösungen für SQLite anzugeben:
Mit dem WAL-Modus (Write-ahead-Protokollierung) können Sie viele Abfragen parallel zur SQLite-Datenbank durchführen
WAL bietet mehr Parallelität, da Leser keine Writer blockieren und a Der Autor blockiert die Leser nicht. Lesen und Schreiben kann weitergehen gleichzeitig.
Vielleicht sind diese Links für Sie interessant:
Tags und Links java multithreading sqlite javafx