Managing threads accessing a database with Java
(I will assume you are using JDBC for your database queries and that you have control over the code running the queries)
I would centralize all database accesses in a singleton class which would keep the last PreparedStatement
running the current query in a single thread ExecutorService
. You could then ask that singleton instance things like isQueryRunning()
, runQuery()
, cancelQuery()
that would be synchronized
so you can decide to show a message to the user whenever the computation should be canceled, cancel it and start a new one.
Something like (add null checks and catch (SQLException e)
blocks):
public class DB { private Connection cnx; private PreparedStatement lastQuery = null; private ExecutorService exec = Executors.newSingleThreadExecutor(); // So you execute only one query at a time public synchronized boolean isQueryRunning() { return lastQuery != null; } public synchronized Future<ResultSet> runQuery(String query) { // You might want to throw an Exception here if lastQuery is not null (i.e. a query is running) lastQuery = cnx.preparedStatement(query); return exec.submit(new Callable<ResultSet>() { public ResultSet call() { try { return lastQuery.executeQuery(); } finally { // Close the statement after the query has finished and return it to null, synchronizing synchronized (DB.this) { lastQuery.close(); lastQuery = null; } } } // Or wrap the above Future<ResultSet> so that Future.cancel() will actually cancel the query } public synchronized void cancelQuery() { lastQuery.cancel(); // I hope SQLite supports this lastQuery.close(); lastQuery = null; }}
A solution to your problem could be Thead.stop()
, which has been deprecated centuries ago (you can find more on the topic here).
To implement the similar behavior it is suggested to use the Thread.interrupt()
, which is (in the context of Task
) the same as the the Task.cancel()
.
Solutions:
- Fill your
calculationMethod
withisCancelled()
checks. - Try to interrupt an underling operation through an other
Thread
.
The second solution is probably what you are looking for, but it depends on the actual code of the calculationMethod
(which I guess you can't share).
Generic examples for killing long database operations (all of this are performed from another thread):
- Kill the connection to the Database (assuming that the Database is smart enough to kill the operation on disconnect and then unlock the database).
- Ask for the Database to kill an operation (eg.
kill <SPID>
).
EDIT:
I hadn't see that that you specified the database to SQLite when I wrote my answer. So to specify the solutions for SQLite:
- Killing the connection will not help
- Look for the equivalent of sqlite3_interrupt in your java SQLite interface
Maybe you can invoke thread instance t1, t1.interrupt() method, then in the run method of thread( Maybe calculationMethod), add a conditional statement.
public void run() { while (!Thread.currentThread().isInterrupted()) { try { // my code goes here } catch (IOException ex) { log.error(ex,ex) } } }