Java Interview Questions

30 Questions
Java

Java

Web DevelopmentBackend

Question 23

What is the 'volatile' keyword in Java?

Answer:

The volatile keyword in Java is used to indicate that a variable's value will be modified by different threads. When a variable is declared as volatile, it ensures that its value is always read from the main memory, and not from the thread's local cache, thereby ensuring visibility of changes across threads.

Key Characteristics of volatile

  1. Visibility: Ensures that changes to a variable are visible to all threads.
  2. Atomicity: Does not guarantee atomicity of compound actions. For example, operations like incrementing a volatile variable are not atomic.
  3. No Caching: Prevents the caching of the variable in thread-local memory.

When to Use volatile

The volatile keyword is useful when you have a variable that is shared between multiple threads, and you need to ensure that changes made by one thread are visible to other threads. It is typically used for flags, state variables, or any variable that is read and written by multiple threads.

Example of Using volatile

Consider a scenario where a flag is used to control the termination of a thread:

public class VolatileExample {
    private volatile boolean running = true;

    public void run() {
        while (running) {
            System.out.println("Thread is running...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Thread stopped.");
    }

    public void stop() {
        running = false;
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileExample example = new VolatileExample();
        Thread thread = new Thread(example::run);
        thread.start();

        Thread.sleep(5000); // Let the thread run for a while

        example.stop(); // Stop the thread
    }
}

Explanation

  1. Declaration:

    private volatile boolean running = true;

    The running variable is declared as volatile, ensuring that any changes made to it are visible to all threads.

  2. Read and Write:

    • The run method continuously checks the value of running.
    • The stop method sets the value of running to false.
  3. Thread Behavior:

    • The main thread starts a new thread that runs the run method.
    • After 5 seconds, the main thread calls the stop method to change the running variable to false, causing the run method to exit the loop and stop the thread.

Volatile vs. Synchronized

  • Volatile:

    • Ensures visibility of changes across threads.
    • Does not provide atomicity for compound actions.
    • Does not block other threads; lightweight compared to synchronized.
    • Suitable for simple flags or state variables.
  • Synchronized:

    • Ensures visibility and atomicity.
    • Provides exclusive access to a block of code or method.
    • Can lead to thread contention and performance overhead due to locking.
    • Suitable for complex operations involving multiple steps or shared data structures.

Example of Volatile Limitation

The volatile keyword does not ensure atomicity for compound actions. For instance:

public class VolatileCounter {
    private volatile int count = 0;

    public void increment() {
        count++; // Not atomic
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        VolatileCounter counter = new VolatileCounter();

        // Create multiple threads that increment the counter
        for (int i = 0; i < 1000; i++) {
            new Thread(counter::increment).start();
        }

        // Wait for a while to let threads finish
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // Output the count
        System.out.println("Count: " + counter.getCount()); // Output might not be 1000
    }
}

In this example, the increment operation (count++) is not atomic, and multiple threads may interfere with each other, leading to incorrect results. To ensure atomicity, you need to use synchronization or AtomicInteger.

Conclusion

The volatile keyword in Java is a useful tool for ensuring visibility of shared variables across threads. It is lightweight compared to synchronization but does not provide atomicity for compound operations. Understanding when and how to use volatile is essential for writing correct and efficient multithreaded programs.

Recent job openings