【发布时间】:2019-05-29 22:39:38
【问题描述】:
编辑:
这个问题是关于解决一个仅使用 Java 代码的问题。该问题是由 SQLLite 间接引起的,但不能通过更改数据库系统或使用 SQL 代码来解决。我提到 SQLLite 是因为否则用户会指向实际上破坏项目强加要求的无用解决方案(定义的用户界面和行为以及作为 DBMS 的 SQLite,因为它可以在没有服务器的情况下运行,并且项目会自动更正)。
EDIT2:
死锁发生在Java端,不容易看到,我调试了一整天才意识到,忘记SQLLite,我需要找到一种方法让Parking像监视器一样工作但是不与synchronized 冲突导致死锁
目前我有以下情况:
我有一个简化的停车类,实际上它是一个监视器,客户端从其他线程调用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 精简版)。
目前代码是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,因为这是一个学校项目。
编辑: 期望的停车行为: 如果用户想借一辆车但它不可用,则用户必须等待其他人从借出的车辆归还。
【问题讨论】:
-
如果 Parking 是唯一使用 ParkingAPI 更新数据库的类,我会说你不需要同步两者。 SQLite 查询位于同步块内,因此它是线程安全的。我不明白为什么 synchronized 关键字对于停车来说是不够的。我不喜欢你的名字。停车API?我希望 ParkingDAO 或 ParkingRepository。
-
除了来自域范围的命名外,如果 2 个用户需要从同一个停车场借出并且只有 1 辆车可用,则想要的行为是一个用户将等待车辆可用,而没有条件变量都将看到车辆数量 == 1 并继续进行借贷查询,这可能很难预测副作用。
-
当然它不是唯一的课程,还有其他的东西,比如注册、登录、添加新的停车场和车辆,除了使用条件变量贷款之外,一切都可以正常工作。
-
听起来 SQLite 是必需的。太糟糕了——我认为你不会在 MySQL 或 PostgreSQL 上遇到那么多问题。可能值得尝试换出数据库,看看情况是否有所改善。
-
如果您使用 BlockingDeque 和生产者/消费者,那么您的问题将很容易解决,没有这些废话:javarevisited.blogspot.com/2012/02/…
标签: java sqlite concurrency synchronized