Concurrency problem when using ConcurrentHashMap

I am working on a REST API as part of some skilling process. My current implementation has a slight concurrency problem when pasting objects into my ConcurrentHashMap.

My code checks if the consumed JSON ID contains. If not, I create a new unique identifier and insert an object. If so, I continue to check if an identifier exists on my card. If the object with the identifier does not exist, I insert the object.

The period between checking whether the HashMap contains a match identifier and inserting an object is a problem when many simultaneous POST requests are executed. A query that has a generated identifier can potentially be written on top of a query in which an identifier was specified if the first query is executed between the lines gcdMap.get(obj.getId()) == nulland the gcdMap.put(obj.getId(), obj);code of the second query. I used Thread.Sleep () to reproduce this problem.

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

I saw suggestions for using locks, but could not implement them in such a way as to solve this problem. We will be very grateful for any examples, documentation or articles that could help me work out a solution.

Editing: in the comments below I was wrong about three times. I can’t edit them now, but I noticed!

+4
1

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

Source: https://habr.com/ru/post/1669228/


All Articles