看一下putIfAbsent界面中默认方法的实现Map,
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
Run Code Online (Sandbox Code Playgroud)
我想知道为什么这个任务
v = put(key, value);
Run Code Online (Sandbox Code Playgroud)
在那里完成而不是简单地丢弃返回的值?这个赋值似乎是不必要的,因为v已经存在null,put根据它的契约,这个方法在这种情况下总是返回.
实现是这样的,因为javadoc声明它应该是:
实施要求:
对于此映射,默认实现等效于:
Run Code Online (Sandbox Code Playgroud)V v = map.get(key); if (v == null) v = map.put(key, value); return v;
但为什么这样指定呢?可能是拿在竞争条件的存在是合理的明确的行为不能得到解决1.
首先,这是javadoc所说的内容.
默认实现不保证此方法的同步或原子性属性.提供原子性保证的任何实现都必须覆盖此方法并记录其并发属性.
那么上面的实现将如何表现呢?
如果没有与另一个线程改变该映射条目的竞争,它将返回null或前一个值(不更新映射).
如果有一场比赛,另一个线程在通话结束后立即更新该条目get,则该map.put通话将不会返回null.相反,它实际上将返回另一个线程插入的值.该值将返回给调用者.
请注意,这与该putIfAbsent方法的主要描述并不完全一致.但这可以通过"无保证"声明来解释.而且,这有点道理.
这有用吗?嗯...可能是的,如果实际的Map方法是线程安全的.因为,如果调用代码想要查看,这将允许它检测到已经发生了竞赛,并且(如果在整个应用程序设计的上下文中有意义的话)尝试对其执行某些操作.
1 - 无法在不了解实现类行为的默认方法中解决竞争条件.例如,可以通过覆盖方法来获得原子属性,从而在实现类本身中解决它们.Mapjavadocs中的方法规范清楚地标明了这种可能性.
但最重要的是,所谓的冗余分配是存在的,因为规范清楚地表明它应该在那里.
| 归档时间: |
|
| 查看次数: |
72 次 |
| 最近记录: |