I have a class DatabaseQueue
which asynchronously runs SQLite updates that it takes from a LinkedBlockingQueue
.
I implemented a pausing mechanism for this class which should ideally stop the execution of the queue as soon as possible and then wait for it to be unpaused before executing more queries.
I'm very new to concurrent programming but I managed to get this working using multiple ReentrantLock
's and Condition
's. This seems very verbose and clumsy though, especially with all the lock()'s and unlock()'s.
In addition to this, I also don't like how I have to execute an additional dummy query just to get the executor thread to continue its loop. What would be a better way to implement this?
import java.sql.Connection;import java.sql.SQLException;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class DatabaseQueue { private static final LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(); private static final QueueExecutor executor = new QueueExecutor(); private static boolean locked = false; private static ReentrantLock lockAttempted = new ReentrantLock(); private static ReentrantLock lockAcquired = new ReentrantLock(); private static Condition attempted = lockAttempted.newCondition(); private static Condition acquired = lockAcquired.newCondition(); public static void start() { if (locked) { locked = false; lockAttempted.lock(); attempted.signal(); //Signal to resume queue execution lockAttempted.unlock(); } else { executor.start(); } } public static void pause() { locked = true; if (queue.isEmpty()) { queue.add("SELECT 1"); } lockAcquired.lock(); acquired.awaitUninterruptibly(); //Wait for the lock to be acquired lockAcquired.unlock(); } public static void queue(String update) { queue.add(update); } public static class QueueExecutor extends Thread { public QueueExecutor() { setName("Database Queue Executor"); setDaemon(true); } @Override public void run() { Connection connection = Database.getConnection(); while (true) { try { if (locked) { lockAcquired.lock(); acquired.signal(); //Signal that the lock has been acquired lockAcquired.unlock(); lockAttempted.lock(); attempted.awaitUninterruptibly(); //Wait for the lock to be released lockAttempted.unlock(); } String update = queue.take(); connection.createStatement().executeUpdate(update); Database.update(update); } catch (InterruptedException | SQLException e) { e.printStackTrace(); } } } }}