Volatile variables' visibility and ordering

In Java, volatile is a keyword used to modify variables. When a variable is declared as volatile, its value will not be cached locally by threads; instead, it is read from and written directly to memory, ensuring visibility and ordering in a multi-threaded environment.

Specifically, when one thread modifies the value of a volatile variable, this modification is immediately visible to other threads, even if they are using different CPU caches. This guarantees the visibility of volatile variables. Additionally, read and write operations on volatile variables are atomic; that is, these operations cannot be interrupted, ensuring the atomicity of volatile variables.

It is important to note that while volatile variables provide a certain level of thread-safety guarantees, they do not ensure the atomicity of compound operations. For example, for a volatile variable i, an i++ operation appears atomic at first glance; however, the i++ operation itself consists of three steps: reading the value, adding 1, and writing the result back. These individual steps are not atomic. Therefore, in such cases, we still need to use the synchronized keyword or other synchronization mechanisms to ensure atomicity.

Below is a simple example demonstrating how to use volatile variables:

public class MyRunnable implements Runnable {
    private volatile boolean stop = false;
    
    public void run() {
        while (!stop) {
            // do something
        }
    }
    
    public void stop() {
        stop = true;
    }
}

In this example, we create a class named MyRunnable that implements the Runnable interface. Within the MyRunnable class, we define a volatile variable named stop to control thread termination. In the run() method, we use a while loop to check the value of the stop variable to determine whether to continue executing the thread. In the stop() method, we set the stop variable to true, thereby halting the thread's execution.

It is important to note that in a multi-threaded environment, if you want to modify the value of a variable or ensure visibility and ordering, you should declare that variable as volatile. However, if you need to guarantee the atomicity of compound operations, you must still implement this using other synchronization mechanisms.