Volatile Keyword in Java Explained

The volatile keyword in Java signals that a variable is being stored in the main memory, ensuring all threads see the same value. Here’s how it differs from other types of keywords in Java, when to use it, how to use it and its limitations.

Written by Alexandru Nastase
Software developer writing in Java
Image: Shutterstock / Built In
Brand Studio Logo
UPDATED BY
Matthew Urwin | Feb 05, 2025

The volatile keyword in Java is a modifier that marks a variable being stored in the main memory. Modifiers are specific keywords present in Java that are used to make changes to the characteristics of a variable, method or class and limit its scope. 

Volatile Keyword in Java Definition

The volatile keyword in Java is a non-access modifier that signals to a thread that a variable is stored in the main memory, not the CPU cache. This ensures that all threads see the same value for the volatile keyword.  

Modifiers in Java are divided into two types — access modifiers and non-access modifiers. Volatile is a non-access modifier.  

More on Software EngineeringJava Switch Case Explained

 

What Is the Volatile Keyword in Java?

The volatile keyword in Java is used to mark a Java variable as “being stored in the main memory.” Every thread that accesses a volatile variable will read it from the main memory and not from the CPU cache. This way, all threads see the same value for the volatile variable.

The volatile keyword can be used with variables of any kind, including primitive types and object references. When used with objects, all threads will see the most up-to-date values for all fields in the object.

A tutorial on how the volatile keyword in Java works. | Video: Visual Computer Science

More on Software EngineeringWhat Is the Java Runtime Environment (JRE)?

 

Volatile Keyword vs. Other Types of Keywords in Java

While the volatile keyword is often associated with other types of keywords in Java, there are clear differences between them. Here are other common types of keywords used in Java and what sets the volatile keyword apart. 

Volatile vs. Atomic

Marking a variable as volatile means declaring that multiple threads will be accessing this variable. This makes the value of the variable visible to all threads. On the other hand, atomicity refers to an operation being indivisible. The atomic keyword hides a process from other threads until it’s been completed, making it appear as if it’s been accomplished in one step and preventing other threads from interfering in the process.    

Volatile vs. Synchronized

Synchronization is an approach that allows only one thread at a time to access a specific section of code. This means that multiple threads cannot alter the block of code, or method, simultaneously. In this way, the synchronized keyword still supports visibility, but it also upholds atomicity by preventing other threads from interfering with a thread executing a task. This stands in contrast to the volatile keyword, which is only concerned with visibility.   

Volatile vs. Transient

Both the volatile and transient keywords involve values, but they focus on different processes. The volatile keyword alerts users that a value can be changed by multiple threads simultaneously. Meanwhile, the transient keyword lets a program know to skip over a variable during serialization — the process of transforming an object’s state into a byte stream. The program then knows not to save the value of the variable. 

Volatile vs. Static

The static keyword ensures that there is only ever one copy of a variable, regardless of how many objects of the class are generated. On the other hand, the volatile keyword enables a variable to be accessed by multiple threads at the same time, and each object created gets its own copy of the variable. This means that the static keyword operates on the class level while the volatile keyword operates on the level of instances or objects.  

 

When to Use the Volatile Keyword

The volatile keyword is usually associated with multithreading, which refers to the ability of a computer program to simultaneously support multiple users without them having to create multiple copies of the program. As a result, multiple users can submit requests to the program at the same time.   

Some scenarios involving multiple threads are ideal for the volatile keyword. It can be used to provide notification when two or more threads want to access specific instructions, when a value is updated by one thread and viewed by other threads and when flags, status indicators and other variables need to be managed. 

While the volatile keyword in programming languages like Java can be applied to primitive data types (boolean, char, byte, int and so on) and object references, it is not considered suitable for complex data structures or mutable objects, as using “volatile” on such objects does not guarantee thread safety for operations that modify their internal state.

In particular, the volatile keyword is often used with flags that indicate a thread needs to stop running. For example, a thread might have a boolean flag called “done”, and when another thread sets this flag to “true”, the first thread will know to stop running. Without the volatile keyword, the first thread might keep running indefinitely, because it would never see the updated value of the “done” flag.

There are other uses for the volatile keyword, but these are some of the most common. In general, if you need to make sure that all threads see the same value for a certain variable, mark that variable as being volatile.

 

How to Use the Volatile Keyword

Before diving into the example below, it’s important to understand what a singleton is. In Java, a singleton is a class that only has one instance, or object, at any given point. The volatile keyword can be applied here, making visible to all threads any changes made when a singleton instance is created. This helps prevent instructions from accidentally being reordered since users can see the work of other threads.

public class Singleton {
    private static volatile Singleton _instance; // volatile variable
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null)
                    _instance = new Singleton();
            }
        }
        return _instance;
    }
}

Breaking Down the Example

In the code above, we’re using the Singleton design pattern in Java, ensuring that only one instance of the Singleton class exists throughout the program.

The class has a private static variable _instance that holds the single instance of the class. The keyword volatile ensures that changes to _instance are immediately visible across multiple threads, preventing caching issues.

In the case of getInstance(), this method is used to get the single instance of the class. The first if (_instance == null) check ensures that we only create an instance if one doesn’t already exist.

If _instance is null, we synchronize on Singleton.class to make sure only one thread at a time can enter. Inside the synchronized block, we check again if _instance is null. This is called double-checked locking. If _instance is still null, we create a new instance.

Without double-checked locking, every thread would synchronize every time getInstance() is called, which is inefficient. By checking _instance == null before and after entering the synchronized block, we only lock when necessary. This improves performance while ensuring thread safety.

Explaining the Role of the Volatile Keyword

If we don’t make the _instance variable volatile, then the thread, which is creating the instance of Singleton, isn’t able to communicate to the other thread. So, if Thread A is creating a Singleton instance, and just after creation, the CPU corrupts, all other threads will not be able to see the value of _instance as not null, and they will believe it is still assigned null.

Why does this happen? Because reader threads aren’t doing any locking, and until the writer thread comes out of a synchronized block, the memory will not be synchronized and the value of _instance will not be updated in main memory. This is handled by Java itself with the volatile keyword, and such updates will be visible by all reader threads.

 

Limitations of the Volatile Keyword

Although the volatile keyword can make life easier for programmers, it still has some downsides that teams must consider to avoid major mistakes.  

Lack of Atomicity

The volatile keyword’s inability to guarantee atomicity can become a larger issue during compound actions. While the volatile keyword can make sure individual actions are visible to all threads, it doesn’t guarantee atomicity for the entire compound operation. This can lead two threads executing the same compound action on the same variable at the same time to produce varying results.  

Potential for Race Conditions

The absence of atomicity also means other threads can interfere in a process if a variable is volatile, creating a race condition. A race condition is a situation where two threads simultaneously access the same data, leading to an unpredictable result that depends on the order in which the threads perform their actions.  

Complications With Arrays

Arrays present another situation where the volatile keyword is ineffective. Marking an array as volatile only applies to their references and doesn’t carry over to their fields. As a result, an array’s value in one thread may still not be visible in other threads.   

Lower Computing Performance

When dealing with the volatile keyword, a computer must read volatile variables from a computer’s main memory instead of its CPU cache. This is a more demanding process that can slow down the computer and decrease its overall performance.

Frequently Asked Questions

The volatile keyword in Java signals that a variable is being stored in memory. Every thread that accesses a volatile variable will read it from main memory ensuring all threads see the same value for the volatile variable.

Non-access modifiers in Java provide information about the characteristics of a class, method, or variable to the JVM. There are seven non-access modifiers, including:

  1. final
  2. static
  3. abstract
  4. synchronized
  5. volatile
  6. transient
  7. native
Explore Job Matches.