353

In the Effective Java book, it states:

The language specification guarantees that reading or writing a variable is atomic unless the variable is of type long or double [JLS, 17.4.7].

What does "atomic" mean in the context of Java programming, or programming in general?

csano
  • 13,266
  • 2
  • 28
  • 45
James
  • 3,541
  • 3
  • 13
  • 4

7 Answers7

460

Here's an example: Suppose foo is a variable of type long, then the following operation is not an atomic operation (in Java):

foo = 65465498L;

Indeed, the variable is written using two separate operations: one that writes the first 32 bits, and a second one which writes the last 32 bits. That means that another thread might read the value of foo, and see the intermediate state.

Making the operation atomic consists in using synchronization mechanisms in order to make sure that the operation is seen, from any other thread, as a single, atomic (i.e. not splittable in parts), operation. That means that any other thread, once the operation is made atomic, will either see the value of foo before the assignment, or after the assignment. But never the intermediate value.

A simple way of doing this is to make the variable volatile:

private volatile long foo;

Or to synchronize every access to the variable:

public synchronized void setFoo(long value) {
    this.foo = value;
}

public synchronized long getFoo() {
    return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized

Or to replace it with an AtomicLong:

private AtomicLong foo;
Flavio Vilante
  • 5,131
  • 1
  • 11
  • 15
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Nice - didn't know that volatile long/double guaranteed atomic assignement. – assylias Feb 24 '13 at 17:26
  • 95
    So this is assuming that it is running in a 32-bit system. What if it was 64 bit system? Will foo = 65465498L; be atomic then? – Harke Dec 24 '13 at 20:36
  • 61
    @Harke If you are running 64 bit Java, yes. – Jeroen Apr 21 '14 at 12:47
  • 4
    Does this applies to C# and .NET too? If yes, in order to foo gets an atomic behavir, the CLR must be 64-bit? – Fabiano Sep 21 '15 at 15:59
  • 5
    @Fabiano It does apply and here's how to achieve it in .NET since we don't have the synchronized keyword like Java. http://stackoverflow.com/questions/541194/c-sharp-version-of-javas-synchronized-keyword – The Muffin Man Nov 18 '15 at 18:22
  • 2
    Then let's assume thread A assigns long value then in half way thread B tries to read it. If operation A is atomic, then thread B will wait till it finishes? This means atomic operations will supply implicit thread-safety? – Teoman shipahi Sep 30 '16 at 13:58
  • @Harke From Java 5.0, 64-bit operations are atomic on 32-bit JVMs as well. – Peter Lawrey Oct 27 '17 at 08:40
  • How `volatile ` or `AtomicLong` guarantees that another thread doesn't see the part value while there are two separate operations ? And at the same time there may has thread context switch between two operations . – shaoyihe Nov 16 '18 at 03:40
  • Please note that the `volatile` keyword used in this way only applies to Java. In C or C++, the `volatile` keyword does not guarantee atomicity, but instead tries to guarantee that a change made in one thread is always visible in another—partial reads and writes are still possible. – mrdecemberist Apr 28 '21 at 17:42
  • In C#/.NET, [several types are guaranteed always atomic](https://stackoverflow.com/questions/2076461/how-does-c-sharp-guarantee-the-atomicity-of-read-write-operations), including object references. For other types, you should use locking or the [Interlocked class](https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked?view=net-5.0). – mrdecemberist Apr 28 '21 at 17:46
89

"Atomic operation" means an operation that appears to be instantaneous from the perspective of all other threads. You don't need to worry about a partly complete operation when the guarantee applies.

H2ONaCl
  • 10,644
  • 14
  • 70
  • 114
  • your second sentence is spot on. "instantaneous", however, is misleading - it's perfectly valid for two atomic operations to be observed in a different order: e.g. `x=0; x=x+1; y=2` in a multithreaded program, a second thread could observe `y=2`, then read `x` is `0` - even if all assignments are atomic. atomic just means that intermediate states of the atomic operations can't be seen. In practice, both compilers and CPUs reorder instructions to improve performance, such that single-threaded code still behaves the same, but the reordering is observable from other threads. – David Goldstein Dec 05 '22 at 07:31
  • @DavidGoldstein you discussed 2 atomic operations. I presume the 2 are the ones that follow `x=0`. In other words, `x=x+1; y=2;`. Anyway if these are 2 atomic operations executed in a different order, it doesn't invalidate my first sentence which tries and I think succeeds in defining an atomic operation, or perhaps I should say defining a single atomic operation. – H2ONaCl Dec 06 '22 at 01:37
  • yeah, that's fair. I guess my point is that people may read "instantaneous" and by analogy with normal expectations of linear time, make the jump to assuming linearizability - where if one operation happens before another, you see the effects in that order as well. Which is not a guarantee individual atomic operations offer when combined. – David Goldstein Dec 07 '22 at 05:29
  • @DavidGoldstein My definition says "appears to be" instantaneous. Most people understand that operations are not actually instantaneous. It's just a metaphor. – H2ONaCl Dec 08 '22 at 13:14
  • @DavidGoldstein By the way, if you're concerned about 2 statements being executed in reverse order, just make the 2 statements or a series of several statements into an atomic operation. Some languages provide this in a feature called a "lock". – H2ONaCl Dec 09 '22 at 05:26
35

It's something that "appears to the rest of the system to occur instantaneously", and falls under categorisation of Linearizability in computing processes. To quote that linked article further:

Atomicity is a guarantee of isolation from concurrent processes. Additionally, atomic operations commonly have a succeed-or-fail definition — they either successfully change the state of the system, or have no apparent effect.

So, for instance, in the context of a database system, one can have 'atomic commits', meaning that you can push a changeset of updates to a relational database and those changes will either all be submitted, or none of them at all in the event of failure, in this way data does not become corrupt, and consequential of locks and/or queues, the next operation will be a different write or a read, but only after the fact. In the context of variables and threading this is much the same, applied to memory.

Your quote highlights that this need not be expected behaviour in all instances.

Grant Thomas
  • 44,454
  • 10
  • 85
  • 129
18

Just found a post Atomic vs. Non-Atomic Operations to be very helpful to me.

"An operation acting on shared memory is atomic if it completes in a single step relative to other threads.

When an atomic store is performed on a shared memory, no other thread can observe the modification half-complete.

When an atomic load is performed on a shared variable, it reads the entire value as it appeared at a single moment in time."

Kurt Zhong
  • 7,308
  • 1
  • 19
  • 15
16

If you have several threads executing the methods m1 and m2 in the code below:

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}

you have the guarantee that any thread calling m2 will either read 0 or 5.

On the other hand, with this code (where i is a long):

class SomeClass {
    private long i = 0;

    public void m1() { i = 1234567890L; }
    public long m2() { return i; }
}

a thread calling m2 could read 0, 1234567890L, or some other random value because the statement i = 1234567890L is not guaranteed to be atomic for a long (a JVM could write the first 32 bits and the last 32 bits in two operations and a thread might observe i in between).

assylias
  • 321,522
  • 82
  • 660
  • 783
  • why do you think that "long" causes problem while "int" does not ? Please see here http://geekswithblogs.net/BlackRabbitCoder/archive/2012/08/09/c.net-little-wonders-interlocked-increment-decrement-and-add.aspx – onmyway133 Sep 26 '13 at 07:28
  • 1
    @entropy long and double assignments are not guaranteed to be atomic in Java. So you could read a long where only half of the bits have been updated following an assignment. – assylias Sep 26 '13 at 07:38
1

In Java reading and writing fields of all types except long and double occurs atomically, and if the field is declared with the volatile modifier, even long and double are atomically read and written. That is, we get 100% either what was there, or what happened there, nor can there be any intermediate result in the variables.

Eugene Shamkin
  • 163
  • 1
  • 3
  • 13
1

In simple words, the atomic means the operation will be either completed or not. The other threads or CPUs won't catch it in the middle of the operation.