修改
这个问题是关于解决仅使用Java代码的问题。问题是由SQLLite间接引起的,但无法通过更改数据库系统或SQL代码来解决。我提到了SQLLite,因为否则用户会指出实际上违反项目强加要求的无用解决方案(定义的用户界面和行为以及SQLite作为DBMS,因为它可以在没有服务器的情况下运行,项目可以自动更正)。
EDIT2:
僵局发生在 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,我必须保护连接不受并发访问的影响(基本上我可以在任何给定时间执行1个查询,因为SQL Lite)。
目前代码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的并发访问是必需的,因为这是一个学校项目。
编辑: 所需的停车行为: 如果用户希望借车并且无法使用,则用户必须等待其他人从贷款中返还车辆。
答案 0 :(得分:2)
此代码:
long lendVehicle(){
lock.lock();
try{
...
}
错了。您基本上锁定然后不能保证解锁,因为它在try
块之外。尝试更恰当地分解问题。你有一个生产者,这是汽车的回馈,然后你的消费者正在借车。所以你知道你的“汽车批次”只能容纳N辆汽车(比如10个清酒)。因此,如果你的缓冲区(汽车地段)已经满了,你不想让更多的汽车被送回(想想试图停在一个没有斑点的车库里)。
现在您可以简单地检查您的返回汽车功能,如果缓冲区已满并且是否忽略该操作。在租车时,你要确保地段不是空的。