2017-02-09 65 views
4

我一直在研究REST API作爲一些技能的一部分。將對象插入到我的ConcurrentHashMap時,我當前的實現有一個小的併發問題。併發問題使用ConcurrentHashMap時

我的代碼檢查消費的JSON是否包含一個ID。如果不是,我創建一個新的唯一ID並插入該對象。如果是,我繼續檢查我的地圖中是否存在該ID。如果沒有存在ID的對象,則插入該對象。

檢查HashMap是否包含匹配的ID並插入對象之間的時間段在發出多個併發POST請求時證明是一個問題。如果在第二個請求的代碼行的第一個請求在gcdMap.get(obj.getId()) == nullgcdMap.put(obj.getId(), obj);之間執行,那麼具有生成的ID的請求可能被指定了ID的請求寫入。我一直在使用Thread.Sleep()來重現這個問題。

public static ConcurrentMap<Long, GCDObject> gcdMap = new ConcurrentHashMap<Long, GCDObject>(); 
@POST 

@Consumes(MediaType.APPLICATION_JSON) 
public GCDObject create(GCDObject obj) throws GCDRequestException { 
    obj.setTimestamp(LocalDateTime.now()); 
    obj.setResult(GCD.calculate(obj.getX(), obj.getY())); 

    if (obj.getId() != null) { // JSON contains ID 
     if (gcdMap.get(obj.getId()) == null) { // If map does not contain obj with ID already, 
      Thread.sleep(1000); 
      gcdMap.put(obj.getId(), obj); // Put obj into map. 
      return obj; 
     } else { // else map already contains ID, 
      throw new GCDRequestException(); 
     } 
    } else { // JSON contains no ID 
     obj.setId(buildId()); // Build ID 
     gcdMap.put(obj.getId(), obj); // Put into map 
     return obj; 
    } 
} 

我已經看到了有關使用鎖的建議,但無法以解決此問題的方式實現它們。任何可能幫助我制定解決方案的示例,文檔或文章都將不勝感激。

編輯:我在下面的評論中拼錯三次缺席。我現在無法編輯它們,但我注意到了!

+1

你使用Java 8? – shmosel

+0

是的,我正在使用Java 8. – Afterfield

+3

您是否嘗試過使用其他ConcurrentHashMap方法(如putIfAbsent&getOrDefault),並且同時發出的POST請求是不同還是相同? –

回答

10

使用putIfAbsent()有條件地插入:

if (gcdMap.putIfAbsent(obj.getId(), obj) == null) { // If map did not contain obj with ID already, 
    return obj; 
} else { // else map already contained ID, 
    throw new GCDRequestException(); 
} 
+0

我給了'putIfAbscent()'另一個鏡頭,它正在做我希望的事情;我想我可能忘記了第一次重建我的項目。謝謝! – Afterfield