Java 如何为ConcurrentHashMap使用并设置适当的并发级别?

Java 如何为ConcurrentHashMap使用并设置适当的并发级别?,java,concurrency,Java,Concurrency,我正在concurrenthashmap中处理大约1000个元素。默认并发级别为16。有人能帮我找出一些算法或因素吗?从这些算法或因素中,我可以确定适合我的场景的并发级别,或者并发级别以何种方式影响多线程的处理 ConcurrentHashMap<String, String> map=new ConcurrentHashMap<String, String>(500,1,20); ConcurrentHashMap=新的Concurre

我正在concurrenthashmap中处理大约1000个元素。默认并发级别为16。有人能帮我找出一些算法或因素吗?从这些算法或因素中,我可以确定适合我的场景的并发级别,或者并发级别以何种方式影响多线程的处理

   ConcurrentHashMap<String, String> map=new ConcurrentHashMap<String, String>(500,1,20);             
ConcurrentHashMap=新的ConcurrentHashMap(500,1,20);
20是我的并发级别(虚拟值)。需要根据文档有效地设置此值:

更新操作之间允许的并发性由 可选的
concurrencyLevel
构造函数参数 (默认值
16
),用作内部大小调整的提示。这个 表是内部分区的,以尝试允许指定的 无争用的并发更新数。因为安置 哈希表本质上是随机的,实际的并发将 变化。理想情况下,您应该选择一个值来容纳尽可能多的对象 线程将同时修改表。使用 远高于您需要的价值可能会浪费空间和时间, 并且显著较低的值可能会导致线程争用

所以你需要回答一个问题:


将同时修改表的线程数是多少?

16是地图将拆分为的默认区域数。
对于读卡器线程,ConcurrentHashMap(在几乎所有情况下)都是在完全没有锁定的情况下完成的。写入线程的数量是您需要担心的。这个数字应该等于你拥有的区域数

ConcurrentHashMap允许多个读卡器在没有任何阻塞的情况下并发读取。这是通过基于并发级别将映射划分为不同的部分并在更新期间仅锁定映射的一部分来实现的。默认并发级别为16,相应地,映射被分为16个部分,每个部分由不同的锁管理。这意味着,16个线程可以同时在Map上操作,直到它们在Map的不同部分上操作为止。这使得ConcurrentHashMap在保持线程安全性不变的情况下仍具有高性能。

Java 8:

现在,
ConcurrentHashMap
根本不使用固定锁条带化方案,而是使用内部同步将每个bucket用作“条带”

源代码:

/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
    ...
    Node<K,V> f; int n, i, fh;
    ...
    else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
    ...
       synchronized (f) {
           ...
       }
}
/**put和putIfAbsent的实现*/
最终V值(K键,V值,仅布尔值){
...
节点f;int n,i,fh;
...
else if((f=tabAt(tab,i=(n-1)&散列))==null){
...
已同步(f){
...
}
}
构造器有一个参数,正如文档所说,只需将其用作大小提示即可

concurrencyLevel—估计的并发更新线程数。实现可以使用此值作为调整大小的提示

资料来源:

public ConcurrentHashMap(int initialCapacity,
                         float loadFactor, int concurrencyLevel) {
    if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
        throw new IllegalArgumentException();
    if (initialCapacity < concurrencyLevel)   // Use at least as many bins
        initialCapacity = concurrencyLevel;   // as estimated threads
    long size = (long)(1.0 + (long)initialCapacity / loadFactor);
    int cap = (size >= (long)MAXIMUM_CAPACITY) ?
        MAXIMUM_CAPACITY : tableSizeFor((int)size);
    this.sizeCtl = cap;
}
公共ConcurrentHashMap(int initialCapacity, 浮点加载因子,int并发级别){ 如果(!(负载系数>0.0f)|初始容量<0 | |并发级别=(长)最大容量)? 最大_容量:tableSizeFor((int)size); this.sizeCtl=上限; }
你不需要自己考虑,<代码> CONCURNESHASMAP 将为你处理它。

所以,并发级别等于写入线程。map也会被分割为与并发级别的值相等。

你知道有多少线程可以同时访问地图吗?这取决于当前登录的用户的否。系统。如果答案是100,那么您可以将并发级别设置为100。@Tala假设我的系统有100个线程。90个线程将遍历此映射,最多10个线程将尝试修改(放置/删除)每次映射一次,那么什么是并发级别?请回答。我会将其设置为10,如果在您的情况下没有线程等待是非常关键的,您可以将其设置为16,例如。从注释到java 8 ConcurrentHashMap实现:我们不想浪费将一个不同的锁对象与每个bin关联所需的空间,所以相反,您可以将其设置为16将bin列表的第一个节点本身作为锁。对这些锁的锁定支持依赖于内置的“同步”监视器。