Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How atomicity is achieved in the classes defined in java.util.concurrent.atomic package?

I was going through the source code of java.util.concurrent.atomic.AtomicInteger to find out how atomicity is achieved by the atomic operations provided by the class. For instance AtomicInteger.getAndIncrement() method source is as follows

public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}

I am not able to understand the purpose of writing the sequence of operations inside a infinite for loop. Does it serve any special purpose in Java Memory Model (JMM). Please help me find a descriptive understanding. Thanks in advance.

like image 302
Vaibhav Raj Avatar asked Jun 05 '13 13:06

Vaibhav Raj


1 Answers

I am not able to understand the purpose of writing the sequence of operations inside a infinite for loop.

The purpose of this code is to ensure that the volatile field gets updated appropriately without the overhead of a synchronized lock. Unless there are a large number of threads all competing to update this same field, this will most likely spin a very few times to accomplish this.

The volatile keyword provides visibility and memory synchronization guarantees but does not in itself ensure atomic operations with multiple operations (test and set). If you are testing and then setting a volatile field there are race-conditions if multiple threads are trying to perform the same operation at the same time. In this case, if multiple threads are trying to increment the AtomicInteger at the same time, you might miss one of the increments. The concurrent code here uses the spin loop and the compareAndSet underlying methods to make sure that the volatile int is only updated to 4 (for example) if it still is equal to 3.

  1. t1 gets the atomic-int and it is 0.
  2. t2 gets the atomic-int and it is 0.
  3. t1 adds 1 to it
  4. t1 atomically tests to make sure it is 0, it is, and stores 1.
  5. t2 adds 1 to it
  6. t2 atomically tests to make sure it is 0, it is not, so it has to spin and try again.
  7. t2 gets the atomic-int and it is 1.
  8. t2 adds 1 to it
  9. t2 atomically tests to make sure it is 1, it is, and stores 2.

Does it serve any special purpose in Java Memory Model (JMM).

No, it serves the purpose of the class and method definitions and uses the JMM and the language definitions around volatile to achieve its purpose. The JMM defines what the language does with the synchronized, volatile, and other keywords and how multiple threads interact with cached and central memory. This is mostly about native code interactions with operating system and hardware and is rarely, if ever, about Java code.

It is the compareAndSet(...) method which gets closer to the JMM by calling into the Unsafe class which is mostly native methods with some wrappers:

public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
like image 196
Gray Avatar answered Nov 04 '22 16:11

Gray