Definition

The volatile keyword in Java is a mechanism that helps achieve visibility of changes to variables across multiple threads. When a variable is declared volatile, it means:

  1. No caching: Threads read the value of the volatile variable directly from the main memory rather than from their thread-local cache.
  2. Happens-before guarantee: Any write to a volatile variable happens before any subsequent read of that variable.

Example

class VolatileExample {
    private static volatile boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        Thread writerThread = new Thread(() -> {
            try {
                // Simulate some processing before setting the flag
                Thread.sleep(1000);
                flag = true;
                System.out.println("Flag set to true by writer thread");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread readerThread = new Thread(() -> {
            while (!flag) {
                // Loop until flag is true
            }
            System.out.println("Flag is now true in reader thread");
        });

        writerThread.start();
        readerThread.start();

        writerThread.join();
        readerThread.join();
    }
}

Output

Flag set to true by writer thread
Flag is now true in reader thread

Feature

  • Changes made to a volatile variable are visible to all threads immediately.
  • Ensures that reads and writes to volatile variables happen in a predictable order.
  • Unlike synchronized, volatile does not introduce locking, meaning it doesn’t block other threads but offers better performance for certain scenarios.
  • It does not guarantee that compound actions (like incrementing a value) are thread-safe.

Advantages

  • It is lighter than using synchronized blocks, as it does not involve locking.
  • Ensures that all threads have the most up-to-date value of a shared variable, preventing data inconsistency issues.
  • Useful in cases where variables are frequently read but rarely updated, providing better performance compared to locks.
  • Ideal for use-cases like status flags (running, isActive, etc.) where visibility is more critical than atomicity.