【问题标题】:Java reenrantlock unlock throws java.lang.IllegalMonitorStateExceptionJava reentrantlock unlock 抛出 java.lang.IllegalMonitorStateException
【发布时间】:2024-01-13 08:18:01
【问题描述】:

线程在执行前需要获取多个锁,所以我把所有的锁放到一个列表中,并迭代tryLock()它们,如果tryLock()成功,我将获取的锁添加到一个名为acquiredLocks的列表中,所以当任何时候lock'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;
    }

【问题讨论】:

  • tryAllLocks 是否被多个线程同时调用?如果是这样,您将在线程之间共享acquiredLocks
  • 如果这不是问题,或者只是问题的一部分,那么请注意,我也没有看到您清除 acquiredLocks
  • acquiredLocks 是每个线程的一个新实例,它不是共享的

标签: java multithreading asynchronous concurrency locking


【解决方案1】:

您忘记在解锁后清除已获取锁的列表。解锁后,它们不再被获取,并且其他线程可以锁定它们:正如您所提到的,您看到来自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;
}

【讨论】:

  • 我想就是这样,虽然 acquireLocks 是每个线程的一个新实例,但锁会在每个 while 循环中添加到 acquireLocks 中,谢谢。我会尝试在办公室修复它 tmr