Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.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 关于Concurrenthashmap的事实_Java_Concurrenthashmap - Fatal编程技术网

Java 关于Concurrenthashmap的事实

Java 关于Concurrenthashmap的事实,java,concurrenthashmap,Java,Concurrenthashmap,我已经从不同的来源阅读了关于ConcurrentHashmap的几条声明,并想验证它们是否确实如此 创建ConcurrentHashmap的迭代器后,只保证反映线程的删除和更新操作。 迭代器是否在编辑/删除后刷新其快照?为什么迭代器对待更新/删除与添加有任何不同 ConcurrentHashmap将其数据切分为多个段,以减少写入器锁争用。concurrencyLevel参数直接指定类在内部创建的碎片数。 如果我们只是使用无参数构造函数,并接受默认配置,映射将在您添加第一个值之前实例化16个碎片所

我已经从不同的来源阅读了关于
ConcurrentHashmap
的几条声明,并想验证它们是否确实如此

  • 创建
    ConcurrentHashmap
    的迭代器后,只保证反映线程的删除和更新操作。 迭代器是否在编辑/删除后刷新其快照?为什么迭代器对待更新/删除与添加有任何不同

  • ConcurrentHashmap
    将其数据切分为多个段,以减少写入器锁争用。
    concurrencyLevel
    参数直接指定类在内部创建的碎片数。 如果我们只是使用无参数构造函数,并接受默认配置,映射将在您添加第一个值之前实例化16个碎片所需的对象… 这里的碎片是什么意思?它是地图中的一个数据桶,还是整个地图的副本。 我理解这类似于数据库中的一个页面,可以在更新时独立锁定。 那么为什么并发级别会影响内存呢


  • 请记住,哈希表只是其核心的一个数组,它有一些巧妙之处,允许您使用非整数键,并且仍然可以获得恒定时间访问

  • 对于add,添加元素可能会导致哈希表增长,从而创建一个新的底层数组并对表中的元素重新排序。散列的迭代器可能会指向旧数组,这样它就可以保留其位置

  • 通常,在这种情况下,切分意味着贴图被分割成若干子阵列,因此您不太可能一次命中多个子阵列。实际上,对于大多数情况,如果指定的碎片数量较少,则效果更好。除非您运行的服务器在该表上存在大量争用,否则2个碎片通常就足够了。另见:

  • 迭代器是否在编辑/删除后刷新其快照?为什么 迭代器对更新/删除的处理与添加不同

    CHM的迭代器在API中解释为

    类似地,迭代器和枚举返回反映 哈希表在创建 迭代器/枚举

    这意味着返回的迭代器可能反映也可能不反映迭代时映射中发生的更改。想象一下,如果创建迭代器并遍历整个段,然后转到下一段。转到下一段后,完成遍历的第一段完成了添加或删除。你看不到,没关系,它没有违反API

    至于你的第二个问题。添加是隐含的,添加和删除之间的可见性并没有区别

    为什么并发级别会影响内存

    自ConcurrentHashMap发布以来,内存一直是一个问题。默认情况下,每个并发级别将创建一个段。这个段有一个HashEntry表,也是一个可重入锁(所以所有必要的东西也是如此)

    Java8实际上解决了这个问题

    您可以阅读有关内存的更多信息,具体如下:

    在做内存配置文件时,JVisualVM显示头号罪犯 是ConcurrentHashMap.Segment类。默认数量的 每个ConcurrentHashMap的段数为16。中的HashEntry表 段可能很小,但每个段都是一个可重入锁。 每个ReentrantLock都包含一个同步,在本例中是一个非空同步,它 是Sync的子类,然后是AbstractQueuedSynchronizer。每个 这些包含一个节点队列,这些节点维护当前状态 发生在你的线程上。在确定公平性时使用。 此队列和节点使用大量内存

  • 如果您引用的是entrySet枚举,这将(最终)反映对父对象执行的添加和删除操作。但是,枚举本身不支持添加操作

  • 本例中的切分本质上是一个哈希表的哈希表。假设ConcurrentHashMap的支持数组包含1024个条目。如果没有切分,这意味着对象的散列值将映射到[01023]之间的整数。使用分片,这意味着支持数组包含16个包含64个条目的支持数组,即[0,1023]支持数组现在是[0,63]中的数组,另一个来自[64,127]的数组,等等。假设您正在修改散列为100的对象-如果不分片,您将锁定整个[0,1023]支持数组,但是使用分片,您只锁定了[64127]子数组,允许其他线程修改其他分片。您拥有的碎片越多,ConcurrentHashMap的并发性就越高,但是碎片越多,维护它们所需的内存就越多。(然而,这不是一种乘法效应,使用16个碎片将使16使用的内存总量相乘。相反,这是一种加法效应;假设维护每个碎片的数据结构需要64个字节,那么使用16个碎片将向数据结构添加1024个字节,使用64个碎片将向数据结构添加4096个字节。)


  • 如何在内部设置它?
    。查看
    ConcurrentHashmap
    的源代码,回答第二点:它们是段。每个段都包含一部分数据。您可以通过对key.hashCode()的哈希来获得正确的段。我不是把它作为一个答案,因为我不确定如何回答第一个问题。只是澄清一下第一个问题-这是否意味着对于迭代器,更新/删除与添加没有什么不同?迭代器是否能够查看更新/删除/添加实际上取决于操作是否发生在“活动”段上。所谓“活动”,我指的是当前处于活动状态的段