31

Recently I was reading a tutorial, in that I came across a statement that says..

"The Java language specification guarantees that reading or writing a variable is an atomic operation(unless the variable is of type long or double). Operations variables of type long or double are only atomic if they declared with the volatile keyword."

AtomicInteger or AtomicLong that provides methods like getAndDecrement(), getAndIncrement() and getAndSet() which are atomic.

I got confused a bit with the above statement.. could you please clarify when to use AtomicInteger or AtomicLong classes.

MaheshVarma
  • 1,982
  • 7
  • 31
  • 54

6 Answers6

57

Doing a = 28 (with a being an int) is an atomic operation. But doing a++ is not an atomic operation because it requires a read of the value of a, an incrementation, and a write to a of the result. As a result, if you used a++ to implement a thread-safe counter, you could have two threads reading the value concurrently (26 for example), then have both increment it and writing it concurrently, resulting in 27 as a result, instead of 28.

AtomicInteger solves this issue by providing atomic operations like the ones you listed. In my example, you would use incrementAndGet() for example, which would guarantee the end value is 28 and not 27.

fredt
  • 22,590
  • 3
  • 37
  • 60
JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174
  • 1
    Then why shall we have to use 'volatile', if we perform operations on variables of type "double" or "long"? – MaheshVarma May 24 '13 at 07:19
  • 7
    If you use an AtomicXxx, you don't need to use volatile, as atomic objects provide more guarantees than volatile. Doing `a++` on a volatile integer doesn't make the operation atomic. It only guarantees the another thread will see the new value of a after it has been incremented. When assigning new values to long or double values, it also guarantees that the write is an atomic operation (because writing to a non-volatile long or double variable consists in writing 4 bytes, then writing the other 4 bytes). Prefer atomic objects over volatile variables in general. – JB Nizet May 24 '13 at 07:26
  • 1
    `a = 28` is not guaranteed to be atomic if `a` is a long or a double, unless it is also volatile. – assylias May 25 '13 at 08:39
  • 1
    @assylias: yes. I didn't repeat that because it was already correctly stated in the question. I'll edit to clarify though. – JB Nizet May 26 '13 at 07:04
  • 1
    long and double are not atomic in 32 bit JVMs because they are 8 bytes. They are atomic in 64 bit JVMs. – fracca Oct 31 '13 at 18:37
  • so, atomicity provides synchronization? –  Jun 19 '17 at 16:26
  • @HarishAmarnath no. Proper synchronization is a way to provide atomicity, though. – JB Nizet Jun 19 '17 at 16:31
  • @JBNizet, then,,atomicity provides synchronization on shared variables/objects ,right? –  Jun 19 '17 at 17:11
  • 1
    Again, no. Atomicity is the concept of doing an operation atomically, i.e. which can't be half-observed by any other thread. It doesn't provide synchronization. – JB Nizet Jun 19 '17 at 17:29
  • a = a+1 or a+=1 or ++a which one is/are atomic operations? – Vishal Singla Jun 20 '19 at 20:01
  • @VishalSingla none. All read the value of a, then increment the value, then write the value to a. – JB Nizet Jun 20 '19 at 20:53
10

Atomic means the operation completes without any possibility for something to happen between. eg. getAndDecrement(), on AtomicInteger, guarantees that the variable is returned AND decremented at the same time.

If it was not an atomic operation, the possibility would exist for the value to get decremented (eg. from 3 to 2), then modified by another thread (eg. changing it from 2 to 5), then returned as 5.

Ren
  • 3,201
  • 2
  • 25
  • 46
4

You need an AtomicInteger if you need to read a variable and write a result depending on the read value. For instance, i++ reads i (e.g. 3) and writes i+1 (e.g. 4). A thread may be interrupted meanwhile, and three other threads increment i too. Now that we get back, i actually has the value 6 but our thread still writes 4, based on what it read beforehand.

AtomicInteger.getAndIncrement ensures you're not interrupted and therefore always incrementing properly. Moreover, the result is always flushed into memory, whereas a non-volatile i might not be flushed to memory. In this case other threads might not even see the changes.

drew moore
  • 28,107
  • 16
  • 72
  • 106
Matthias Meid
  • 12,080
  • 6
  • 41
  • 73
1

atomicity of an operation is required when you mutate a variable. doing int a = 10; is an atomic operation but its not the one which will give you the problem. the problem giving operations usually are mutating ones like a++ or a = a + 2; and so on.

Java Specification guarantees that 'reading' and 'writing' are atomic operations not their combinations. so an operation which 'reads, adds 1 and then writes the result back' is not atomic as per specification. such operations are called compound operations and they usually need to be atomic in context of their usage in our code.

Atomic types help solve this problem. using incrementAndget() on an atomic type makes 'reads, adds 1 and then writes the result back and reads the new result' a single atomic operation in context to thread safety.

Hope this helps. By the way you should read this (http://walivi.wordpress.com/2013/08/24/concurrency-in-java-a-beginners-introduction/) article about basics of concurrency and threads. it explains such stuff beautifully.

Nazgul
  • 1,832
  • 1
  • 11
  • 13
0

I think what it means is that long and double - read operation is atomic and write operation is atomic. But a read + write is not atomic.

volatile long num;
num = num+1

The above is not thread safe. There read and write are two separate operations. Each of those are guaranteed to be atomic, but the whole expression is not.

To make it thread safe you would need to use an AtomicLong and use the getAndIncrement function.

gkamal
  • 19,552
  • 4
  • 55
  • 57
  • It says the exact opposite: in `long a; a = 1;`, the second statement is not guaranteed to be atomic. – assylias May 25 '13 at 08:36
  • no it doesn't - "Operations variables of type long or double are only atomic if they declared with the volatile keyword", notice the volatile – gkamal May 25 '13 at 11:17
  • Your first sentence is misleading with no reference to volatile. – assylias May 25 '13 at 12:14
0

You use int or long based on the upper/lower limit on the range of numbers you are dealing with. Please do not mix non-atomic behavior of long with AtomicLong. Whatever you have written above is correct but you are probably mixing both concepts. AtomicXXX are more useful in cases where you are doing "compare & set" kind of operations. For example even when int can be modified/read atomically following code will be incorrect in multithreaded environment :

int i =10
..
..
..
if(i == 10) i++;

in multithread environment two threads can access this code atomically and updated value of i and making it come in consistent state. SO deal with such situations normally you guard the code "if(i == 10) i++;" with synchronized block. However AtomicInteger class provides the API to achieve such things without using synchronized blocks which are slower. Same is the case of AtmoicLong APIs

Saurabh
  • 7,703
  • 2
  • 20
  • 29