java - 在我的情况下是 Lock+HasMap 还是 ConcurrentHashMap?

标签 java concurrency thread-safety java-7 concurrenthashmap

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

这是我的建议。

  1. 继续使用ConcurrentHashMap。您仍然需要放入到 map 中,您也可以使用 CHM 安全地完成此操作。

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

  3. 如果您无法执行 (2),则从 map 在队列上同步

所以 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以等于成功放入的队列。如果一个线程获胜(queue == null为真),那么我们将分配该队列为我们的队列 创建(我们是获胜线程)。

关于java - 在我的情况下是 Lock+HasMap 还是 ConcurrentHashMap?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30169932/

相关文章:

java - != 检查线程安全吗?

java - 确定服务实例是否正在运行并终止它

java - 使用 Pico 编译器 - Ipad 运行时,在 Java 中使用 switch() 和 Scanner 会出现错误

java - Spring 异步和分时度假

java - 应该如何处理 javax.persistence.OptimisticLockException?

go - 如果我正确使用 channel ,我是否需要使用互斥体?

iOS 确保每个 session 只调用一次函数

java - 从 ThreadSafeClientConnManager 连接池取消/中止连接

java - 如何查找一个数字是否包含在java中的数字范围数组中

java - Collectors.toList() 返回什么样的 List<E>?