Volatile and Synchronized Keywords in Java

Java provides two important keywords, volatile and synchronized, which play a crucial role in multi-threaded programming. These keywords help in ensuring visibility and atomicity, respectively, when dealing with shared variables and concurrent access from multiple threads.

The Volatile Keyword

The volatile keyword is used to indicate that a variable may be modified by multiple threads and therefore needs to be accessed directly from the main memory. It guarantees that changes made to the variable by one thread are immediately visible to other threads.

When a variable is declared as volatile, the JVM ensures that changes made by one thread are not stored in a cache, but in the main memory directly. Other threads reading the value will always get the most up-to-date value from the main memory instead of relying on a cached value.

public class VolatileExample {
    private volatile boolean isRunning = true;
    
    public void stop() {
        isRunning = false;
    }
    
    public void start() {
        while (isRunning) {
            // perform some task
        }
    }
}

In the example above, the isRunning variable is declared as volatile. This guarantees that any change made to it by another thread will be immediately visible within the start() method. Without the volatile keyword, the start() method might cache the value of isRunning and never exit the loop, even if stop() is called from another thread.

The Synchronized Keyword

The synchronized keyword is used to create a mutually exclusive block of code known as a synchronized block. It ensures that only one thread can enter the synchronized block at a time, preventing multiple threads from simultaneously modifying the same shared variables, thereby avoiding data inconsistencies.

There are two ways to use the synchronized keyword:

  1. Synchronized block: We can define a block of code to be executed exclusively by one thread at a time.

    public class SynchronizedExample {
        private int count = 0;
        
        public void increment() {
            synchronized (this) {
                count++;
            }
        }
    }

    In the example above, the increment() method is synchronized on the instance of the SynchronizedExample class itself. Only one thread will be able to access and modify the count variable at a time.

  2. Synchronized method: We can define an entire method to be executed exclusively by one thread at a time.

    public synchronized void increment() {
        count++;
    }

    In this approach, the entire increment() method is synchronized, and only one thread can execute it at a time. The synchronization is automatically applied to the instance of the object on which the method is called.

Synchronization can also be applied to static methods or blocks to achieve mutually exclusive access among threads operating on static variables.

Volatile vs Synchronized

While volatile ensures visibility of variables across threads and prevents caching, it does not provide atomicity. On the other hand, synchronized ensures both visibility and atomicity, as it allows only one thread to execute the synchronized code block at a time.

It is important to note that the overuse of synchronized can lead to performance degradation, as it introduces thread contention. Therefore, volatile is usually preferred when there is a single simple variable that requires thread visibility, while synchronized is useful for more complex scenarios that involve multiple variables or operations.

In summary, volatile is used when variables are simple and independent, while synchronized is used when we need to maintain consistency or synchronization between multiple threads accessing shared resources.

Conclusion

The volatile and synchronized keywords are powerful tools in Java to handle multi-threaded programming challenges. They help in maintaining thread visibility and synchronization, ensuring the correct execution and consistency of concurrent programs. Understanding their differences and when to apply each one is crucial for writing efficient and thread-safe code.


noob to master © copyleft