Search code examples
javaconcurrencyconcurrenthashmap

Updating both a ConcurrentHashMap and an AtomicInteger safely


I have to store words and their corresponding integer indices in a hash map. The hash map will be updated concurrently.

For example: lets say the wordList is {a,b,c,a,d,e,a,d,e,b} The the hash map will contain the following key-value pairs

a:1
b:2
c:3
d:4
e:5

The code for this is as follows:

public class Dictionary {

private ConcurrentMap<String, Integer>  wordToIndex;
private AtomicInteger                   maxIndex;

public Dictionary( int startFrom ) {
    wordToIndex = new ConcurrentHashMap<String, Integer>();
    this.maxIndex = new AtomicInteger(startFrom);
}


public void insertAndComputeIndices( List<String> words ) {

    Integer index;
    //iterate over the list of words
    for ( String word : words ) {
        // check if the word exists in the Map
        // if it does not exist, increment the maxIndex and put it in the
        // Map if it is still absent
        // set the maxIndex to the newly inserted index

        if (!wordToIndex.containsKey(word)) {
            index = maxIndex.incrementAndGet();

            index = wordToIndex.putIfAbsent(word, index);
            if (index != null)
                maxIndex.set(index);
        }
    }
}

My question is whether the above class is thread safe or not? Basically an atomic operation in this case should be to increment the maxIndex and then put the word in the hash map if it is absent.

Is there a better way to achieve concurrency in this situation?


Solution

  • Clearly another thread can see maxIndex incrementing and then getting clobbered.

    Assuming this is all that is going on to the map (in particular, no removes), then you could try putting the word in the map and only incrementing if that succeeds.

        Integer oldIndex = wordToIndex.putIfAbsent(word, -1);
        if (oldIndex == null) {
            wordToIndex.put(word, maxIndex.incrementAndGet());
        }
    

    (Alternatively for a single put, use some sort of mutable type in place of Integer.)