Jor*_*Joh 0 java multithreading thread-synchronization
真的有必要lock.unlock()在一个finally街区吗?下面是一个常见的习语
try {
lock.lock();
// some code
} catch (Exception e) {
// exception handling
} finally {
lock.unlock();
}
Run Code Online (Sandbox Code Playgroud)
然而,Java 语言规范是这样说的:
如果主体的执行曾经完成,无论是正常还是突然 [大概,例如由于异常],都会在同一监视器上自动执行解锁操作。
那么真的有必要加lock.unlock()块吗?finally或者我误解了规范?
您链接的Java 语言规范(JLS)部分正在讨论synchronized. 具体来说,它是说如果您有以下情况:
synchronized (someObj) {
// guarded code
}
Run Code Online (Sandbox Code Playgroud)
然后,当该synchronized块因任何原因退出时,包括从块内抛出异常,都可以保证隐式监视器someObj将被解锁。
APIjava.util.concurrent.locks是一个单独的东西,JLS 没有涵盖(尽管显然依赖于 JLS 定义的 Java 内存模型 (JMM))。这意味着您必须阅读 API 的 Javadoc 才能了解其定义如何工作。
以下是软件包文档的摘录:
接口和类提供了锁定和等待条件的框架,这与内置同步和监视器不同 [强调]。该框架在使用锁和条件方面提供了更大的灵活性,但代价是语法更加尴尬。
这是文档的摘录Lock:
随着灵活性的增加,责任也随之增加。块结构锁定的缺失消除了
synchronized方法和语句中发生的锁的自动释放 [强调]。在大多数情况下,应该使用以下习惯用法:Run Code Online (Sandbox Code Playgroud)Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
正如您所看到的,需要解锁finally块1中的锁。另请注意,对的调用lock()是在块之前try完成的。这可以防止在调用因lock()任何原因失败的情况下尝试解锁锁。
1. 创建 API 的一个主要原因java.util.concurrent.locks是为了提供比synchronized. 您可能有一个更复杂的场景,您需要在unlock()远离调用的地方lock()或在未来某个未指定的时刻进行调用,这意味着unlock()在finally块中调用可能不是正确的方法。但正如文档所指出的,这意味着您(开发人员)有更多的责任。由您来保证unlock()在适当的时候被调用。