You appear to be accidentally reusing the same AtomicInteger
value with different keys. When you place an AtomicInteger
into the map, it can be re-used when you call get
.
Here's what's going on:
Input: AAA
It doesn't exist yet, so one
is placed in the map.
Input: A
It doesn't exist yet, so one
is placed in the map. There are now two references to one
in the map.
Input: AA
It doesn't exist yet, so one
is placed in the map. There are now three references to one
in the map.
Input: B
It doesn't exist yet, so one
is placed in the map. There are now four references to one
in the map.
Input: A
A
already exists, so the value is retrieved. Now count
refers to the same object as one
! count
is incremented, but a copy is made. Now AAA
, AA
, and B
are still mapped to the original AtomicInteger
, but it's now wrong; it's 2
. However, A
refers to a second AtomicInteger
, which is correct at 2
.
Input: AAA
AAA
already exists, so the value is retrieved. Now count
refers to the same object as one
, again! count
is incremented, but a copy is made. Now, AA
and B
are still mapped to the original AtomicInteger
, but it's now wrong; it's 3
. However, A
refers to the second AtomicInteger
still, and it's still correct at 2
. Additionally, AAA
refers to a third AtomicInteger
, but it's still wrong at 3
.
Solution
Change when you create new AtomicInteger
objects, and just increment when you don't need new ones; they're mutable.
for (String key : stuff) {
AtomicInteger count = A.get(key);
if (count == null)
A.put(key, new AtomicInteger(1));
else
count.incrementAndGet(); // Modifies the object referred to in the map.
}