EDIT:
This question is about resolving a problem using only Java code. The problem is caused by SQLLite indirectly but cannot be solved by changing Database system or with SQL code. I mention SQLLite because otherwise users would point to useless solutions that actually breaks project imposed requirments (A defined user interface and behaviour and SQLite as DBMS because it can run without server and projects are subject to automatic correction).
EDIT2:
The deadlock happens on Java side, it is not easy to see it, I debugged for a whole day before realizing that, forget about SQLLite, I need to find a way to get Parking working like a monitor but without conflicting with synchronized
causing a deadlock
Currently I have the following situation:
I Have a simplified Parking class, actually it is a monitor where clients call the lendVehicle
method from other threads.
public class Parking{
private final long parkId;
private final ParkingAPI sqlLayer;
private final Lock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
public Parking( long mparkId, ParkingAPI api){
sqlLayer = api;
parkId = mparkId;
}
long lendVehicle(){
lock.lock();
try{
while(sqlLayer.countVehicles(parkId) == 0)
notEmpty.await();
return sqlLayer.lend(parkId);
} finally{
lock.unlock();
}
}
void giveBackVehicle(long vehicleId){
lock.lock();
try{
sqlLayer.giveBack(vehicleId,parkId);
notEmpty.signal();
} finally{
lock.unlock();
}
}
When I mock the SQL layer with just an atomic counter, the class works perfectly, however since the application is using SQL Lite I have to protect the connection from concurrent access (basically I can execute 1 query at any given time because of SQL Lite).
Currently the code is synchronized
over the DBLayer
object (wich is shared across all classes).
class ParkingQuery implements ParkingAPI{
private final DBLayer connection;
public SQLLayer(DBLayer db){
connection = db;
}
@Override
int lend(long parkId){
synchronized( connection){
return connection.lendVehicleFromPark(parkId);
}
}
@Override
int countVehicles(long parkId){
synchronized( connection){
return connection.countVehiclesQuery(parkId);
}
}
@Override
void giveBack(long vehicleId, long parkId){
synchronized( connection){
connection.giveBackVehicle(parkId, vehicleId);
}
}
}
The problem is the synchronized part, wich does not play well with the Parking's monitor: wich in fact cause a deadlock.
How can I preserve functionality of parking? (Can't remove synchronized on ParkingQuery because SQLite just explode if queries are not synchronized and bad things starts happening).
Note that concurrent access to SQLLite is mandatory because that's a school project.
EDIT: Desired parking behaviour: If a user desire lending a vehicle and it is not available the user have to wait someone else returns back a vehicle from lending.