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 汽车功能是否缓冲区已满,如果它是忽略操作。借车时要确保车位不是空的。
编辑:
这个问题是关于 仅使用 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 汽车功能是否缓冲区已满,如果它是忽略操作。借车时要确保车位不是空的。