2015-05-11 43 views
1

我有一個Map<String, Queue<?>>和每次我必須把幾個(鍵,值)我需要得到不是線程安全的隊列與該鍵相關聯,並添加一個值(如果存在鍵)。因爲我需要更新現有的值(隊列),我認爲最好的方法是使用ReentrantLock(同步塊或同步(對象)在Java < 1.5中)而不是ConcurrentHashMap。在我的情況下,Lock + HasMap或ConcurrentHashMap?

是否正確或我可以使用ConcurrentHashMap而不是HashMap + Lock?我認爲ConcurrentHashMap在獲取操作方面效率更高,但我不知道這裏是否可能是正確的解決方案。

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(); 
      } 
     } 
} 

該代碼是正確的還是可以更高性能?

+0

你期望地圖有多少爭用? –

+0

是的,你應該避免在兩種方法中進行雙重獲取。調用'get()'並檢查結果爲null而不是調用'containsKey()'。 – jtahlborn

+0

是的,你可以通過使用ConcurrentHashMap來實現這個更高性能,因爲你可以減少對每個特定隊列的鎖定,而不是爲每個更新鎖定所有隊列。 – jtahlborn

回答

2

所以你有兩個獨立的原子指令需要同步。

  1. 把一個新的隊列進入地圖
  2. 把一個對象插入到隊列

這裏是我的建議。

  1. 繼續使用ConcurrentHashMap。您仍然需要put進入地圖,您也可以使用CHM安全地執行此操作。使用BlockingQueue。在這種情況下,您可以使用PriorityBlockingQueue

  2. 如果您不能從Map執行(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的唯一區別是不存在的​​。

我們知道這是線程安全的原因是因爲即使2個或更多線程輸入if(queue == null)只有一個將在putIfAbsent成功。丟失的線程將分配queue以等於已成功投入的隊列。如果線程獲勝(隊列== null爲true),則我們將分配隊列爲創建的一個我們(我們正在獲勝的線程) 。