Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Map'中的冗余分配;s的putIfAbsent实现_Java - Fatal编程技术网

Java Map'中的冗余分配;s的putIfAbsent实现

Java Map'中的冗余分配;s的putIfAbsent实现,java,Java,查看界面Map中默认方法putIfAbsent的实现 default V putIfAbsent(K key, V value) { V v = get(key); if (v == null) { v = put(key, value); } return v; } 我想知道为什么要做这个作业 v = put(key, value); 是在那里完成的,而不是简单地丢弃返回值?这个赋值似乎没有必要,因为v已经是null,这就是put方法根据其

查看界面
Map
中默认方法
putIfAbsent
的实现

default V putIfAbsent(K key, V value) {
    V v = get(key);
    if (v == null) {
        v = put(key, value);
    }

    return v;
}
我想知道为什么要做这个作业

v = put(key, value);

是在那里完成的,而不是简单地丢弃返回值?这个赋值似乎没有必要,因为
v
已经是
null
,这就是
put
方法根据其约定在这种情况下始终返回的值。

它必须始终返回旧值

如果映射由多个线程访问,则
put
返回的值可能与
get
返回的值不同,因此分配给
v
可以确保更好的行为


当然,代码不适合处理多线程访问,因此任何有效的线程安全实现都会覆盖该方法以使其更好,但这是通用默认实现所能达到的最佳效果。

实现是这样的,因为它的状态应该是:

实施要求:

对于此映射,默认实现相当于:

 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-无法在不了解实现类行为的默认方法中解决争用条件。它们可以在实现类本身中解决。。。例如,通过重写该方法使其具有原子属性。而
    Map
    javadocs中的方法规范清楚地标记了这种可能性



    但归根结底,这种所谓的冗余分配是存在的,因为规范明确指出它应该存在。

    我的猜测是,它解释了可能存在的竞争条件。此方法不是原子操作。在
    get
    put
    调用之间,键值关联可能已经更新。我考虑的是并发而不是警告,但是
    putIfAbsent
    文档中的短语“默认实现不保证此方法的同步性或原子性属性”表明情况并非如此。也许这是为了安全起见,正如回答中提到的。IMO这是一个糟糕的执行决定。如果
    put
    中的值不同于
    get
    ,则该方法仍会更新键值对,而且返回值为非null,这通常表示
    put
    实际上没有发生。这不是实现决策。这是一个规格决定。看看我的答案。改变行
    v=put(key,value)不是更好的设计决策吗
    if(put(key,value)!=null)抛出新的ConcurrentModificationException()?不。并发集合不会引发该异常。此外,正如我所解释的,指定的行为是可预测和有用的。但如果设计得更好的话,它真的不会改变任何争论。