我想实现一个线程安全的队列映射。
我打算从一张空地图开始。如果密钥不存在,我想创建一个带有新队列的新Map条目。如果密钥确实存在,我想添加到Queue。我建议的实施如下:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class StackOverFlowExample {
private final Map<String, ConcurrentLinkedQueue<String>> map = new ConcurrentHashMap<>();
public void addElementToQueue(String key, String value){
if (map.containsKey(key)){
map.get(key).add(value);
}
else{
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.add(value);
map.put(key, queue);
}
}
}
我担心的是,当多个线程尝试向Map添加新值时,第一个将使用新的Queue放置一个新的Map条目,第二个将等待,然后为该键添加一个新的Queue,而不是而不是添加到队列。我的并发/并发API知识充其量只是渺茫。也许并发就地是为了避免这种情况?建议将不胜感激。
答案 0 :(得分:3)
此模式可能已在SO上多次发布(有效添加到并发映射):
Queue<String> q = map.get(key);
if(q == null) {
q = new ConcurrentLinkedQueue<String>();
Queue<String> curQ = map.putIfAbsent(key, q);
if(curQ != null) {
q = curQ;
}
}
q.add(value);
答案 1 :(得分:0)
所以你担心线程A和线程B将执行以下操作:
thread A: lock ConcurrentHashMap
Look for Queue "x" (not found)
unlock ConcurrentHashMap
create Queue "x"
lock ConcurrentHashMap
Insert Queue X
unlock ConcurrentHashMap
Thread B:
Lock ConcurrentHashMap (while thread A is in 'create Queue X')
look for queue X (not found)
unlock ConcurrentHashMap (thread A then gets lock)
create Queue "x" v2
lock ConcurrentHashMap
Insert Queue X v2 (overwriting the old entry)
unlock ConcurrentHashMap
这实际上是一个真正的问题,但通过使AddElementToQueue成为同步方法可以轻松解决这个问题。然后在任何给定时间内AddElementToQueue中只能有一个线程,因此第一个&#39;解锁&#39;第二个锁定&#39;已关闭。
因此
public synchronized void addElementToQueue(String key, String value){
应解决您的丢失队列问题。
答案 2 :(得分:0)
如果Java 8是一个选项:
public void addElementToQueue(String key, String value) {
map.merge(key, new ConcurrentLinkedQueue<>(Arrays.asList(value)), (oldValue, coming) -> {
oldValue.addAll(coming);
return oldValue;
});
}