我正在使用 concurrenthashmap 中的大约 1000 个元素。默认并发级别为 16 。谁能帮助我一些算法或因素,我可以从中确定适合我的场景的并发级别,或者并发级别以何种方式影响多个线程的处理。
ConcurrentHashMap<String, String> map=new ConcurrentHashMap<String, String>(500,1,20);
20 是我的并发级别(虚拟值)。需要有效地设置它
我正在使用 concurrenthashmap 中的大约 1000 个元素。默认并发级别为 16 。谁能帮助我一些算法或因素,我可以从中确定适合我的场景的并发级别,或者并发级别以何种方式影响多个线程的处理。
ConcurrentHashMap<String, String> map=new ConcurrentHashMap<String, String>(500,1,20);
20 是我的并发级别(虚拟值)。需要有效地设置它
根据文档:
更新操作之间允许的并发由可选的
concurrencyLevel
构造函数参数(默认值16
)引导,该参数用作内部大小调整的提示。该表在内部进行了分区,以尝试允许指定数量的并发更新而不会发生争用。因为哈希表中的放置本质上是随机的,所以实际的并发性会有所不同。 理想情况下,您应该选择一个值来容纳尽可能多的线程同时修改表。使用显着高于您需要的值会浪费空间和时间,而显着降低的值会导致线程争用。
所以你需要回答1个问题:
将同时修改表的线程数是多少?
爪哇 8:
现在ConcurrentHashMap
根本不使用固定的锁条带化方案,而是使用内部同步每个桶充当“条带”。
源代码:
/** 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) {
...
}
}
并且构造函数的参数只是将其用作文档所说的大小提示。
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
会为你处理。
ConcurrentHashMap 允许多个读取器同时读取而不会阻塞。这是通过根据并发级别将 Map 划分为不同的部分并在更新期间仅锁定 Map 的一部分来实现的。默认并发级别为 16,因此 Map 分为 16 个部分,每个部分由不同的锁管理。这意味着,16 个线程可以同时对 Map 进行操作,直到它们对 Map 的不同部分进行操作。尽管保持线程安全完好无损,这使得 ConcurrentHashMap 具有高性能。
16 是地图将被分割成的默认区域数。在读取线程的情况下,ConcurrentHashMap(几乎在所有情况下)完全没有锁定。编写器线程的数量是您需要担心的事情。这个数字应该等于你拥有的区域数。
所以,并发级别等于写入线程。并且map也会分段等于并发级别的值。