此锁管理代码段是否不必要地复杂化?

时间:2017-05-07 14:20:29

标签: java locking fortify

Hewlett Packard Enterprise应用程序Fortify On Demand包含标题为&#34的示​​例代码段;示例2:以下代码将始终释放锁定。"

ReentrantLock  myLock = new ReentrantLock();

try {
    myLock.lock();
    performOperationInCriticalSection();
    myLock.unlock();
}
finally {
    if (myLock != null) {
        myLock.unlock();
    }
}

为什么try块中的最后一行解锁时,finally已经处理了?它真的有必要,还是仅仅是一些冗长的编码标准的一部分? if看起来也不必要。

1 个答案:

答案 0 :(得分:1)

该代码throws an IllegalMonitorStateException,因为它连续两次调用unlock()

来自ReentrantLock.unlock

  

<强>抛出:

     

IllegalMonitorStateException - 如果当前线程没有持有此锁

我不得不说代码不正确,我无法猜测他们想要做什么。如果在myLock = null;块内的unlock()之后立即有try,它可以正常工作,但这样做仍然是草率的代码。如果unlock()抛出异常,那么第二次调用unlock()也会抛出另一个异常。

正确的习语是这样的,根据例如Lock

Lock l = ...;
l.lock();
try {
    // access the resource protected by this lock
} finally {
    l.unlock();
}

如果您想要非常安全,可以使用 try-with-resources 来利用close()引发异常而{{1}引发异常的事实正在抛出块,try异常被添加到被抑制的异常中,因此它们都不会丢失。 (在前面的示例和HP示例中,如果close()抛出异常,则从unlock()块抛出的异常将完全丢失。)

try

Here's an example output using that code on Ideone.

或者你可以写代码which try-with-resources translates to

class Locker implements AutoCloseable {
    private final Lock lock;
    Locker(Lock lock) { this.lock = Objects.requireNonNull(lock);
                        this.lock.lock(); }
    @Override public void close() { lock.unlock(); }
}

Lock lock = ...;
try (Locker locker = new Locker(lock)) {
    // If both modifySharedState() and unlock()
    // throw an exception, the unlock() exception
    // is added to the modifySharedState()
    // exception's suppressed list.
    modifySharedState();
}

但这有点难以理解。

如果逻辑比Lock lock = ...; lock.lock(); Throwable primary = null; try { modifySharedState(); } catch (Throwable x) { primary = x; throw x; } finally { try { lock.unlock(); } catch (Throwable x) { if (primary != null) { primary.addSuppressed(x); // primary is already "in-flight" // so no need to throw it again } else { throw x; } } } 复杂,例如如果你有多个锁或者unlock()是有条件的,那么lock()...unlock()抛出异常的会计可能是有意义的原因。