Volatile Variables and Visibility

Honey Keny Malviya
Agile Architect’s Blog
3 min readMar 4, 2019

--

JVM takes full advantage of the performance of modern multiprocessor hardware. In absence of synchronization, the Java Memory Model permits the compiler to reorder operations and cache values in register, and permits CPUs to reorder operations and cache values in processor-specifics caches.

Therefore, there is no guarantee that the operations in one thread will be performed in the order given by the program, as long as the reordering is not detectable from within that thread — even if the reordering is apparent to other threads.

We not only want to prevent one thread from modifying the state of an object while another is using it, but we also need to ensure that when a thread modifies the state of an object, other threads can actually see the changes that were made.

Always use proper synchronization whenever data is shared across threads.

Insufficiently synchronized programs can cause surprising results: stale data. Unless synchronization is used, every-time a variable is accessed, it is possible to see stale data. Stale data can cause unexpected exceptions, corrupted data structures, inaccurate computations, and infinite loop.

When a thread reads a variable without synchronization, it may see a stale value, but atleast it sees a value that was actually placed there by some thread rather than some random value. This is called Out-of-thin-air safety. It applies to all variables except 64-bit numeric variables (double and long) that are not declared volatile. The JVM memory model requires fetch-and-store operation to be atomic. But for non-volatile long and double variables, the JVM is permitted to treat a 64-bit read or write as two separate 32-bit operation.

Intrinsic locking is not just about mutual exclusion, it also guarantees memory visibility provided the reading and writing threads must synchronize on a common lock.

Volatile Variable

When a field is declared volatile, the compiler and the run-time are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors. So a read of a volatile variable always returns the most recent write by any thread. Volatile reads are only slightly more expensive than nonvolatile reads on most current processor architectures.

Good use of volatile include ensuring the visibility of their own state, than that of the object they refer to, or indicating that an important life-cycle event (such as initialization or shutdown or status flags) has occurred. Volatile variables are convenient, but they have limitations. The semantics of volatile variables are not strong enough to make the increment operation atomic.

Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.

Use volatile variable only when:

  • Writes to a volatile variable do not depend on its current value; or you can ensure that only a single thread ever updates the value.
  • The variable does not participate in invariants with other state variables;
  • Locking is not required for any other reason while the variable is being accessed.

--

--

Honey Keny Malviya
Agile Architect’s Blog

Agile Software Architect | AI & ML | Java | Spring Boot | Angular 6 | AWS | SCRUM Master