有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在我的例子中是java锁+HasMap还是ConcurrentHashMap?

我有一个Map<String, Queue<?>>,每次我必须放入一对(键,值),我需要获取与该键关联的非线程安全队列,并向其添加一个值(如果键存在)。因为我需要更新现有的值(队列),所以我认为最好的方法是使用ReentrantLock(Java中的synchronized块或synchronized(object))<;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) 个答案

  1. # 1 楼答案

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

    1. 将新队列放入映射中
    2. 将对象放入队列

    以下是我的建议

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

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

    3. 如果无法执行(2),则从映射中对队列执行synchronize

    So 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的缺失

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