These are three independent properties a concurrent operation may or may not have. Visibility is whether one thread sees another's writes. Atomicity is whether an operation is indivisible (no interleaving in the middle). Ordering is whether operations appear to execute in program order across threads. A correct concurrent program needs the right combination, and different tools provide different subsets.
Visibility
Without synchronization, a write by thread A may sit in a register, store buffer, or per-core cache and never reach thread B. B can read a stale value indefinitely. volatile, synchronized, and final (after construction) all establish the happens-before edges that force visibility.
Atomicity
An action is atomic if it cannot be observed half-done. Reads and writes of references and most primitives are atomic individually — but compound actions are not. i++ is read-modify-write; if (x == null) x = new T() is check-then-act. Two threads interleaving in the middle corrupt the result.
volatile int n = 0;
void inc() { n++; } // VISIBLE but NOT atomic: lost updates under contention
AtomicInteger a = new AtomicInteger();
void incSafe() { a.incrementAndGet(); } // atomic AND visible (CAS)
The first method shows that visibility alone does not give atomicity: n is always seen freshly, yet increments are still lost.
Ordering
The compiler and CPU reorder independent instructions. Within a thread you never notice; another thread can. Ordering is what makes the "writes appeared out of order" bugs possible, and it's fixed by the memory barriers that volatile writes/reads and lock release/acquire insert.
tool | visibility | atomicity | ordering --------------|------------|------------------|--------- plain field | no | single r/w only | no volatile | yes | single r/w only | yes synchronized | yes | yes (the block) | yes Atomic* (CAS) | yes | yes (one var) | yes final (post-ctor)| yes | n/a | yes