编辑:
这个问题是关于仅使用Java代码解决问题的。该问题是由SQLLite间接引起的,但是无法通过更改数据库系统或使用SQL代码来解决。我之所以提到SQLLite,是因为否则用户会指向无用的解决方案,这些解决方案实际上会破坏项目施加的要求(已定义的用户界面和行为以及SQLite作为DBMS,因为它可以在没有服务器的情况下运行,并且项目可以自动更正)。
编辑2:
僵局发生在Java端,这不容易看到,我整整调试了一天,然后才意识到,忘记了SQLLite,我需要找到一种方法来使Parking像监视器一样工作,而又不与synchronized
冲突僵局
目前我有以下情况:
我有一个简化的Parking类,实际上是一个监视器,客户端从其他线程调用lendVehicle
方法。
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();
}
}
当我仅使用原子计数器模拟SQL层时,该类可以正常运行,但是由于应用程序正在使用SQL Lite,因此我必须保护连接免受并发访问(由于SQL Lite,基本上我可以在任何给定时间执行1个查询) 。
当前,代码位于
synchronized
对象上的DBLayer
(所有类均共享)。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);
}
}
}
问题是同步部分,在停车场的显示器上无法很好地发挥作用:实际上会导致死锁。
如何保留停车功能? (无法删除对ParkingQuery的同步,因为如果查询未同步并且不良情况开始发生,SQLite只会爆炸)。
请注意,必须并发访问SQLLite,因为这是一个学校项目。
编辑:
所需的停车行为:
如果用户希望借出车辆而该车辆不可用,则用户必须等待其他人将车辆从借出归还。
最佳答案
这段代码:
long lendVehicle(){
lock.lock();
try{
...
}
是错的。您基本上是锁定的,因此它不能保证解锁,因为它在
try
块之外。尝试更适当地解决该问题。您有一个生产者,这是汽车的回赠,然后您的消费者将汽车借出。因此,您知道您的“车位”只能容纳N辆车(例如,假设10辆)。因此,如果您的缓冲区(车位)已满,则您不想让更多的车退还(请考虑将车停在没有任何停车位的车库中)。现在,您可以简单地检查回车功能,如果缓冲区已满并且忽略该操作。在借车时,您要确保批次不空。