апр 182020
 

One time I needed to use a counter for some heavy loaded process in multithread environment. As usual, I use the class java.util.concurrent.atomic.AtomicInteger, the methods incrementAndGet and decrementAndGet. But when I put these methods in only two places, absolutely synchronized by calls (increment and decrement counter in short time gap), I got a strange behavior with the counter — it constantly goes down to negative values. When I tried to view source code (OpenJDK 8), I saw this:

/**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

So, instead of incrementing value concurrently and returning new value after this, we have a function call, which returns a current value and increments value by one in the same place. May be this function (getAndAddInt) really increments value of AtomicInteger… or may be not, in this place we don’t know, because we know nothing about new value — we simply return old value + 1.

I found the same behavior in OpenJDK11 source code:

public final int incrementAndGet() {
    return U.getAndAddInt(this, VALUE, 1) + 1;
}

And the same code up to OpenJDK14: https://github.com/openjdk/jdk14u/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java

Moreover, I wrote simple code with a volatile field and two methods for increasing/decreasing this field with ReentrantLock. And using this methods in the same places, where I used AtomicInteger methods, I got a different result — my counter was increased and decreased and had more plausible value, than AtomicInteger.