我一直在研究REST API作爲一些技能的一部分。將對象插入到我的ConcurrentHashMap時,我當前的實現有一個小的併發問題。併發問題使用ConcurrentHashMap時
我的代碼檢查消費的JSON是否包含一個ID。如果不是,我創建一個新的唯一ID並插入該對象。如果是,我繼續檢查我的地圖中是否存在該ID。如果沒有存在ID的對象,則插入該對象。
檢查HashMap是否包含匹配的ID並插入對象之間的時間段在發出多個併發POST請求時證明是一個問題。如果在第二個請求的代碼行的第一個請求在gcdMap.get(obj.getId()) == null
和gcdMap.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;
}
}
我已經看到了有關使用鎖的建議,但無法以解決此問題的方式實現它們。任何可能幫助我制定解決方案的示例,文檔或文章都將不勝感激。
編輯:我在下面的評論中拼錯三次缺席。我現在無法編輯它們,但我注意到了!
你使用Java 8? – shmosel
是的,我正在使用Java 8. – Afterfield
您是否嘗試過使用其他ConcurrentHashMap方法(如putIfAbsent&getOrDefault),並且同時發出的POST請求是不同還是相同? –