Lock+HasMap 或 ConcurrentHashMap 在我的例子中?

Lock+HasMap or ConcurrentHashMap in my case?

我有一个Map<String, Queue<?>>,每次我必须放一对(键,值)时,我需要获取与该键关联的非线程安全队列并向其添加一个值(如果键存在)。因为我需要更新现有值(队列),所以我认为最好的方法是使用 ReentrantLock(Java < 1.5 中的同步块或同步(对象))而不是 ConcurrentHashMap。

这是正确的还是我可以使用 ConcurrentHashMap 而不是 HashMap + Lock?我认为 ConcurrentHashMap 在 get 操作方面效率更高,但我不知道这里是否是正确的解决方案。

    private static ReentrantLock lock_Vqueue = new ReentrantLock();
    private static HashMap<String,Queue<DocumentObjectHolder>> cacheData = new HashMap<String,Queue<DocumentObjectHolder>>();
        /**
         * insert element in the tail 
         * sort the elements by priority 
         * @param obj a DocumentObjectHolder Object
         */
        public static void add(String key, DocumentObjectHolder obj){
            ReentrantLock lock = lock_Vqueue; //performance side effect
            try{
                Queue<DocumentObjectHolder>priorityProcessingVirtualQueue;
                lock.lock();
                    if (!cacheData.containsKey(key)){
                        priorityProcessingVirtualQueue = new PriorityQueue<DocumentObjectHolder>(1, new PriorityComparator());
                        cacheData.put(key, priorityProcessingVirtualQueue);
                    }
                    priorityProcessingVirtualQueue = cacheData.get(key);
                    priorityProcessingVirtualQueue.add(obj);
                    cacheData.put(key, priorityProcessingVirtualQueue);
            }finally {
                lock.unlock();
            }
        }

        /**
         * 
         * @return DocumentObjectHolder instance from head of list (FIFO)
         */
        public DocumentObjectHolder get(String key){
            ReentrantLock lock = lock_Vqueue; //performance side effect
            Queue<DocumentObjectHolder>priorityProcessingVirtualQueue;
            try {
                lock.lock(); 
                 if (cacheData.containsKey(key)){
                     priorityProcessingVirtualQueue = cacheData.get(key);
                     return priorityProcessingVirtualQueue.poll();
                 }
                 return null;
            }finally{
                lock.unlock();
            }
        }
}

这段代码是正确的还是可以提高性能?

所以你有两个单独的原子指令需要同步。

  1. 正在将新队列放入地图
  2. 正在将对象放入队列

这是我的建议。

  1. 继续使用ConcurrentHashMap。您仍然需要 put 进入地图,您也可以使用 CHM 安全地完成它。

  2. 使用一个BlockingQueue。在这种情况下,您可以使用 PriorityBlockingQueue

  3. 如果您不能执行 (2),则 synchronize 从地图排队。

所以 1 和 3 看起来像:

    public static void add(String key, DocumentObjectHolder obj){
        Queue<DocumentObjectHolder> priorityProcessingVirtualQueue= cacheData.get(key);
        if(priorityProcessingVirtualQueue== null){
             Queue<DocumentObjectHolder> temp = new PriorityQueue<DocumentObjectHolder>(1, new PriorityComparator());
             queue = cacheData.putIfAbsent(key, temp);
             if(priorityProcessingVirtualQueue== null){ 
                  priorityProcessingVirtualQueue= temp;
             } 
        }
        synchronized(priorityProcessingVirtualQueue){
            priorityProcessingVirtualQueue.add(obj);
        }
    }

1 和 2 的唯一区别是缺少 synchronized

我们之所以知道这是线程安全的,是因为即使有 2 个或更多线程进入 if(queue == null),也只有一个会在 putIfAbsent 中成功。失败的线程将分配 queue 等于成功放入的队列。如果线程获胜(队列 == null 为真),那么我们将分配队列为 we 已创建(我们是获胜线程)。