Reputation: 3701
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
ordouble
[JLS, 17.4.7].
What does "atomic" mean in the context of Java programming, or programming in general?
Upvotes: 369
Views: 228375
Reputation: 1227
According to Oracle,
In programming, an atomic action is one that effectively happens all at once. An atomic action cannot stop in the middle: it either happens completely, or it doesn't happen at all. No side effects of an atomic action are visible until the action is complete.
The shared resource in multithreading usually causes complex issues when concurrency is applied. The program or database may become inconsistent if a shared resource is impacted. Handling with the shared resource becomes essential where multiple threads access and modify shared resources. In such a case, one of the options may be an atomic variable. And there is no need of explicit synchronization using synchronized
or volatile
keyword.
Java package java.util.concurrent.atomic
provides the following atomic classes to enable lock free mechanism and thread safety.
When two threads work simultaneously on a shared variable and one of those actions involves writing, both threads have to employ atomic operations. The operations of atomic classes in Java depend on CAS(Compare-And-Swap) to perform atomically, ensuring correctness and efficiency of the program in a multithreaded environment.
For Float and Double type variables, there is no atomic classes in this package. But you can use this technique described here.
Upvotes: 0
Reputation: 864
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.
Upvotes: 4
Reputation: 692121
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;
Upvotes: 473
Reputation: 183
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.
Upvotes: 1
Reputation: 328815
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).
Upvotes: 17
Reputation: 7486
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."
Upvotes: 21
Reputation: 11309
"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.
Upvotes: 92
Reputation: 45068
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.
Upvotes: 38