Amplification AtomicIntegerAndGet atomicity

AtomicInteger.incrementAndGet () is atomic as per the documentation. However, in its source code below, what if another thread alternates just before "return next"? "Next" will be incorrect?

public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return next; } } 
+7
java atomicity java.util.concurrent
source share
6 answers

If another thread alternates, it will also successfully add it to the value.

Atomicity ensures that your increment happens, and if two threads try to increment, then two threads will succeed (and increase by two). This does not guarantee anything about any future value.

In your scenario, it looks like this:

 public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) { // Other thread. for (;;) { long current2 = get(); long next2 = current2 + 1; if (compareAndSet(current2, next2)) { return next2; } } return next; } } } 

i.e. each thread gets its own incremental value.

+6
source share

The value increases with each correct call, so the only thing it can affect is the return value.

The semantics of the function is that it does not return the current value of the integer, but the value to which the call to incrementAndGet() increased the integer (updated value).

Let me give an example:

 public MyClass { private AtomicInteger counter; public int getNextUniqueIndex() { return counter.getAndIncrement(); } } 

Now, if you call getNextUniqueIndex() , it will always return a unique value regardless of the calling thread or the rotation of the threads. This is because the next value returned from the implementation of incrementAndGet() refers to the value updated by this call to incrementAndGet() .

+3
source share

What is “right”?

The following value is not the current AtomicInteger value, but the value obtained by incrementing the "current" value.

Assume the next simulation (thus, “stream 2” alternates between “stream 1” just before “return next”)

 i = 10 Thread 1 calling 'j = incrementAndGet(i)' computing incrementAndGet(i) by Thread 1 now i = 11 Thread 2 calling 'm = incrementAndGet(i)' computing incrementAndGet(i) by Thread 2 now i = 12 Thread 1 now j = 11 Thread 2 now m = 12 Thread 3 calling 'n = incrementAndGet(i)' // Hey! It should be only with Thread 1 and 2! now i = 13 and n = 13 

Indeed, incrementAndGet was atomic. What for? Because Thread 1 is called incrementAndGet when I was 10 and get 11. And Thread 2 is called incrementAndGet when I was 11 and get 12. It doesn't matter if I change. After incrementAndGet, the caller receives the resulting value after the increment.

+2
source share

If after compareAndSet , then yes, incrementAndGet can put a higher value in some other thread. However, the same thing will happen after returning. The value would increase by two (correctly), and both threads would get a different value.

This forms the "correct" semantics. With parallel threads, there is no perfect time synchronization.

+2
source share

The compareAndSet method guarantees update atomicity, however there is no guarantee that the return value is "last". incrementAndGet only guarantees that 1) the value has been increased atomically and 2) that you get the result of this increment. What happened before (or after) a successful increment is not related to the current Thread .

+2
source share

The incrementAndGet uses compareAndSet and uses unsafe.compareAndSwapInt. This method atomically updates a Java variable to a given integer if it currently holds the expected integer.

Therefore, when two threads try to increase the value, the JVM will atomically compare the existing value, if it is the same, then the increment will be successful, otherwise it will not be successful.

+1
source share

All Articles