2017-02-09 17 views
4

Я работаю над REST API как часть некоторого процесса skilling. Моя текущая реализация имеет небольшую проблему параллелизма при вставке объектов в мою ConcurrentHashMap.Проблема параллелизма при использовании ConcurrentHashMap

Мой код проверяет, содержит ли потребленный JSON ID. Если нет, я создаю новый уникальный идентификатор и вставляю объект. Если да, я продолжаю проверять, существует ли идентификатор на моей карте. Если объект с идентификатором не существует, я вставляю объект.

Период между проверкой того, содержит ли HashMap идентификатор соответствия и вставка объекта, является проблемой при выполнении многих одновременных запросов POST. Запрос, который имеет сгенерированный идентификатор, может быть потенциально написан поверх запроса, в котором идентификатор был указан, если первый запрос выполнен между gcdMap.get(obj.getId()) == null и gcdMap.put(obj.getId(), obj); строками кода второго запроса. Я использовал 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