在ConcurrentHashMap的 javadoc中有以下内容:
检索操作(包括get)通常不会阻塞,因此可能与更新操作(包括put和remove)重叠.检索反映了最近完成的更新操作的结果.对于诸如putAll和clear之类的聚合操作,并发检索可能反映仅插入或删除某些条目.类似地,Iterators和Enumerations在迭代器/枚举的创建时或之后的某个时刻返回反映哈希表状态的元素.它们不会抛出ConcurrentModificationException.但是,迭代器设计为一次只能由一个线程使用.
这是什么意思?如果我尝试同时使用两个线程迭代地图会发生什么?如果我在迭代时从地图中添加或删除值会发生什么?
java concurrency multithreading thread-safety concurrenthashmap
ConcurrentHashMap的JavaDoc 说:
类似
Hashtable
但不同HashMap
,这个类就不会允许null
用作键或值.
我的问题:为什么?
第二个问题:为什么Hashtable不允许null?
我使用了很多HashMaps来存储数据.但是当更改为ConcurrentHashMap时,由于NullPointerExceptions,我遇到了几次麻烦.
我们正在用C++开发一个高性能的关键软件.我们需要一个并发的哈希映射并实现一个.所以我们写了一个基准来弄清楚我们的并发哈希映射与之比较慢多少std::unordered_map
.
但是,std::unordered_map
似乎是非常慢......所以这是我们的微基准测试(对于并发映射,我们产生了一个新的线程,以确保锁定不会被优化掉,并注意我从来没有inser 0因为我也基准测试google::dense_hash_map
,需要一个空值):
boost::random::mt19937 rng;
boost::random::uniform_int_distribution<> dist(std::numeric_limits<uint64_t>::min(), std::numeric_limits<uint64_t>::max());
std::vector<uint64_t> vec(SIZE);
for (int i = 0; i < SIZE; ++i) {
uint64_t val = 0;
while (val == 0) {
val = dist(rng);
}
vec[i] = val;
}
std::unordered_map<int, long double> map;
auto begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < SIZE; ++i) {
map[vec[i]] = 0.0;
}
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
std::cout << "inserts: " << …
Run Code Online (Sandbox Code Playgroud) 在Java中,ConcurrentHashMap
是否有更好的multithreading
解决方案.那我ConcurrentSkipListMap
什么时候应该用?这是一种冗余吗?
这两者之间的多线程方面是否常见?
前段时间,我发表了一篇关于递归计算斐波纳契数的Java 8函数式方法的博文,其中包含一个ConcurrentHashMap
缓存和新的有用computeIfAbsent()
方法:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Test {
static Map<Integer, Integer> cache = new ConcurrentHashMap<>();
public static void main(String[] args) {
System.out.println(
"f(" + 8 + ") = " + fibonacci(8));
}
static int fibonacci(int i) {
if (i == 0)
return i;
if (i == 1)
return 1;
return cache.computeIfAbsent(i, (key) -> {
System.out.println(
"Slow calculation of " + key);
return fibonacci(i - 2) + fibonacci(i - 1);
});
}
} …
Run Code Online (Sandbox Code Playgroud) 我一直在使用Java的ConcurrentMap作为可以从多个线程使用的地图.putIfAbsent是一个很好的方法,比使用标准的map操作更容易读/写.我有一些看起来像这样的代码:
ConcurrentMap<String, Set<X>> map = new ConcurrentHashMap<String, Set<X>>();
// ...
map.putIfAbsent(name, new HashSet<X>());
map.get(name).add(Y);
Run Code Online (Sandbox Code Playgroud)
可读性明智这很好,但它确实需要每次创建一个新的HashSet,即使它已经在地图中.我可以这样写:
if (!map.containsKey(name)) {
map.putIfAbsent(name, new HashSet<X>());
}
map.get(name).add(Y);
Run Code Online (Sandbox Code Playgroud)
通过此更改,它会失去一点可读性,但不需要每次都创建HashSet.在这种情况下哪个更好?我倾向于支持第一个,因为它更具可读性.第二个会表现得更好,也可能更正确.也许有比这两种方法更好的方法.
以这种方式使用putIfAbsent的最佳做法是什么?
ConcurrentHashMap
在Java中有什么用?它有什么好处?它是如何工作的?示例代码也很有用.
刚刚在ConcurrentHashMap计算方法中发现了这个奇怪的代码:(第1847行)
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
...
Node<K,V> r = new ReservationNode<K,V>();
synchronized (r) { <--- what is this?
if (casTabAt(tab, i, null, r)) {
binCount = 1;
Node<K,V> node = null;
Run Code Online (Sandbox Code Playgroud)
因此代码对仅可用于当前线程的新变量执行同步.这意味着没有其他线程可以竞争这种锁定或导致内存阻塞效应.
这个动作有什么意义?这是一个错误还是会引起一些我不知道的不明显的副作用?
ps jdk1.8.0_131
JDK中附带了CopyOnWrite*
用于实现Set
和List
,但没有对Map
和我常常感叹这个事实.我知道有其他的集合实现有它们,但如果一个标准出货将是很好的.这似乎是一个明显的遗漏,我想知道它是否有充分的理由.任何人都知道为什么这被遗漏了?
我在多线程环境中聚合键的多个值.钥匙事先不知道.我以为我会这样做:
class Aggregator {
protected ConcurrentHashMap<String, List<String>> entries =
new ConcurrentHashMap<String, List<String>>();
public Aggregator() {}
public void record(String key, String value) {
List<String> newList =
Collections.synchronizedList(new ArrayList<String>());
List<String> existingList = entries.putIfAbsent(key, newList);
List<String> values = existingList == null ? newList : existingList;
values.add(value);
}
}
Run Code Online (Sandbox Code Playgroud)
我看到的问题是,每次运行此方法时,我都需要创建一个新的实例,ArrayList
然后将其丢弃(在大多数情况下).这似乎是无理滥用垃圾收集器.是否有一种更好的,线程安全的方法来初始化这种结构而不必使用synchronize
该record
方法?我对使该putIfAbsent
方法不返回新创建的元素的决定感到有些惊讶,并且缺少一种延迟实例化的方法,除非它被调用(可以这么说).
java ×9
concurrency ×3
map ×2
performance ×2
c++ ×1
c++11 ×1
collections ×1
hashmap ×1
java-8 ×1
recursion ×1
stl ×1