java - Java reenrantlock unlock 抛出 java.lang.IllegalMonitorStateException
问题描述
线程在执行前需要获取多个锁,所以我把所有的锁都放到一个列表中,并迭代tryLock()它们,如果tryLock()成功,我将获得的锁添加到一个名为acquidLocks的列表中,所以当任何锁'tryLock () 失败,我可以解锁已经获取的锁,但是当回滚发生时,它会通过 ReenrantLock 抛出 java.lang.IllegalMonitorStateException,因为当前线程没有持有该锁。我检查了acquiredLocks列表,其中的一些锁确实是由另一个线程获取的,但是我在将它添加到acquiredLocks列表之前调用了tryLock()。
private final List<Lock> locks = new CopyOnWriteArrayList<>();
private final List<Lock> acquiredLocks = new CopyOnWriteArrayList<>();
/**
* try to acquire all locks, if any lock is not acquired, roll back and release all already acquired
* locks
*/
private boolean tryAllLocks() {
for (Lock lock : locks) {
if (lock.tryLock()) {
acquiredLocks.add(lock);
} else {
acquiredLocks.forEach(Lock::unlock);
return false;
}
}
return true;
}
public PriceGenerationAggregate call() throws Exception {
try {
if (TenorConst.isSpotTenor(marketPriceCache.getTenor())) {
this.priceGenerationAggregate = new SpotRootPriceGenerationAggregate(marketPriceCache, synchronizeForwardSpotPrice());
} else {
this.priceGenerationAggregate = new ForwardRootPriceGenerationAggregate(marketPriceCache);
}
for (GenerationProduct generationProduct : priceGenerationAggregate.getAllSubscribedPriceForPriceGeneration().getAllGenerationProducts()) {
Lock lock = ProductLockCache.getLock(generationProduct.getCcyPair(), generationProduct.getTenor(), generationProduct.getVolume());
locks.add(lock);
}
// try all the locks before the price generation
while (!tryAllLocks()) {
Thread.sleep(100);
}
generatePrices();
} catch (Exception e) {
e.printStackTrace();
} finally {
releaseAllLocks();
}
return priceGenerationAggregate;
}
解决方案
您忘记在解锁后清除已获取锁的列表。解锁后,它们不再被获取,并且其他线程可以锁定它们:正如您提到的,您看到锁acquiredLocks
被其他线程持有。
解锁后添加一条语句(这仅在每个线程都有一个列表的新实例acquiredLocks.clear();
的假设下有效)。acquiredLocks
private boolean tryAllLocks() {
for (Lock lock : locks) {
if (lock.tryLock()) {
acquiredLocks.add(lock);
} else {
acquiredLocks.forEach(Lock::unlock);
acquiredLocks.clear(); // <-- added
return false;
}
}
return true;
}
推荐阅读
- c++11 - 从 QStackedLayout 中的 QWidget 中删除框架
- string - 为什么 string.Replace 在 golang 中不起作用
- apache-kafka - 确定kafka topic中每个partition的数据大小
- angular - index.d.ts 的角度需要什么?它与“declare var pluginName:any”有何不同
- angular - 在 Angular 6 中显示动态引导弹出内容
- sql - SQL 查询为用户生成每周和每日登录持续时间(使用 SQL Server 2016)
- c - 将 xmlDoc 嵌套到现有的 xmlTextWriter
- java - Java/OpenJDK:如何将 JAR 添加到类路径
- nlp - 我有一个关于 NLP 中命名实体识别的实际实现的问题
- c++ - 如何将对象指针与动态数组一起使用