为啥 Java 8 没有在 `java.util.concurrent.locks.Lock` 接口中添加 `withLock` 默认方法?
Posted
技术标签:
【中文标题】为啥 Java 8 没有在 `java.util.concurrent.locks.Lock` 接口中添加 `withLock` 默认方法?【英文标题】:Why didn't Java 8 add `withLock` default methods to the `java.util.concurrent.locks.Lock` interface?为什么 Java 8 没有在 `java.util.concurrent.locks.Lock` 接口中添加 `withLock` 默认方法? 【发布时间】:2014-06-04 09:51:56 【问题描述】:和this question一样,我想知道为什么Java团队没有在Lock接口中添加一些默认方法,像这样:
public default void withLock(Runnable r)
lock();
try
r.run();
finally
unlock();
这将允许程序员这样做
public class ThreadSafe
// Object requiring protection
private final List<String> l = new ArrayList<>();
private final Lock lock = new ReentrantLock();
public void mutate(String s)
lock.withLock(() -> l.add(s));
public void threadSafeMethod
lock.withLock(() -> System.out.println(l.get(l.size())); );
而不是
public void threadSafeMethod
lock.lock();
try
System.out.println(l.get(l.size()));
finally
lock.unlock();
【问题讨论】:
【参考方案1】:这个问题的答案似乎与the linked question 的答案相似——它被认为是“令人讨厌的麻烦”,因为从 lambda 创建的Runnable
的分配成本(参见Brian Goetz's response 到请求)。
好消息是这个请求有 an open bug,这意味着一旦 JVM 能够可靠地最小化分配成本,Oracle 似乎愿意重新考虑这个决定。
【讨论】:
作为旁注,Brian 的示例withLock( () -> counter++; );
不可能是捕获 lambda,因为该示例中的 counter
不能是局部变量。但我们明白了这一点,实际上,你不能在这样的 withLock
中改变本地变量,或者发出 return
和其他提前退出控制语句的限制,可能是反对它的更有力的论据。跨度>
@Marko Topolnik:示例() -> counter++
是 一个捕获 lambda 但它仅在 counter
是成员变量时才有效,因此 lambda 记住对 @987654332 的不可变引用@(或 static
变量的类)。请注意,如果 counter
是一个局部变量,那么不仅 lambda 不起作用,它还会使整个示例变得毫无意义,因为没有理由对 local 变量的更新应该由 @ 保护987654335@.
@Holger 似乎存在术语不一致:我的意思是它不是一个 closure 因为它不会关闭局部变量(我认为这与“捕获 lambda”)。这意味着该示例没有展示任何性能问题,因此无法解释为什么 withLock
未包含在 API 中。如果counter
是本地变量,您的补充说明该示例将无效。
@Marko Topolnik:Brian Goetz 的解释针对的问题是,对于当前的 lambda 实现,当 lambda 具有状态 (see my explanation here) 时,每次调用都会创建一个新实例。不管是捕获this
还是counter
,在这种情况下有用的lambda 总是有状态,因此每次都会产生一个新实例。所以他关于“捕获”的说法是正确的。但是,当所有其他 API 都忽略它时,我不明白为什么这个小性能问题会推动 API 设计决策……
@Holger 一个合理的预期是可以从this
引用的对象访问this
捕获的 lambda,而不涉及任何哈希表支持的 lambda 缓存。另外,我认为您使用的术语“调用站点”不是指调用站点,而是指 lambda 创建站点。以上是关于为啥 Java 8 没有在 `java.util.concurrent.locks.Lock` 接口中添加 `withLock` 默认方法?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在此示例中我没有收到 java.util.ConcurrentModificationException?
java.util.Collection 为啥不实现新的 Stream 接口?
为啥我在使用 java.util.zip.ZipFile 打开空 ZIP 文件时出现异常?