线程安全的队列图

时间:2014-10-21 21:13:21

标签: java multithreading queue concurrenthashmap

我想实现一个线程安全的队列映射。

我打算从一张空地图开始。如果密钥不存在,我想创建一个带有新队列的新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知识充其量只是渺茫。也许并发就地是为了避免这种情况?建议将不胜感激。

3 个答案:

答案 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;
    });
}