Java: 帮助设计解决由 SQLite 引起的死锁

Java: Help design out deadlock caused by SQLLite

编辑:

这个问题是关于 仅使用 Java 代码 来解决问题的。此问题是由 SQLLite 间接引起的,但无法通过更改数据库系统或使用 SQL 代码来解决。我提到 SQLLite 是因为否则用户会指向实际上破坏项目强加要求的无用解决方案(定义的用户界面和行为以及 SQLite 作为 DBMS 因为它可以 运行 没有服务器和项目会自动更正)。

编辑2: 死锁发生在Java侧,不容易看出来,调试了一整天才发现,忘了SQLLite,我需要找到一种方法让 Parking 像监视器一样工作,但又不会与 synchronized 冲突导致死锁


目前我的情况如下:

我有一个简化的 Parking class,实际上它是一个监视器,客户端从其他线程调用 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 层时,class 工作得很好,但是由于应用程序使用的是 SQL Lite,我必须保护连接不受并发影响访问(基本上我可以在任何给定时间执行 1 个查询,因为 SQL Lite)。

目前代码是 synchronized DBLayer 对象(所有 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);
        }
    }
}

问题出在同步部分,它不能很好地与停车场的监视器配合使用:实际上会导致死锁。

如何保留停车功能? (无法在 ParkingQuery 上删除同步,因为 SQL如果查询不同步并且坏事开始发生,网站就会爆炸)。

请注意,并发访问 SQLLite 是强制性的,因为这是一个学校项目。

编辑: 期望的停车行为: 如果用户希望借出车辆但无法使用,则用户必须等待其他人 returns 借出车辆。

此代码:

long lendVehicle(){
        lock.lock();
        try{
          ...
    }

错了。你基本上锁定然后它不能保证解锁,因为它在 try 块之外。尝试更恰当地分解问题。你有一个生产者,这是汽车的回馈,然后你的消费者正在借出汽车。所以您知道您的 "car lot" 只能容纳 N 辆汽车(例如,假设 10 辆)。因此,如果您的缓冲区(停车场)已满,您不想让更多的汽车归还(考虑尝试将车停在没有停车位的车库中)。

现在您可以简单地检查您的 return 汽车功能是否缓冲区已满,如果它是忽略操作。借车时要确保车位不是空的。