Java Memory Model and Threads (3): Rules for Volatile Variables

Volatile variables are generally difficult to understand. Here I hope to list a few small examples so that everyone can fully understand how to use it.

For variables with volatile defined, there are two characteristics to keep in mind:

First, ensure that this variable is visible to all threads. The visible line here means that a thread modifies the value of this variable, and the new value is known to other threads. Here, there is no consistency problem with volatile variables, and volatile variables are not safe under concurrent conditions. This is illustrated by a program:

package cn.edu.hust.jvm;

public class MainTest {


    public static volatile int value=0;

    public static void incr()
    {
        value++;
    }

    public static void main(String[] args)
    {
        Thread[] threads=new Thread[10];
        for (int i=0;i<10;i++)
        {
            threads[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j=0;j<1000;j++)
                    {
                        incr();
                    }
                }
            });
            threads[i].start();
        }
        System.out.println(value);
    }
}

If the volatile variable is concurrency safe, then the output should be 10000, the actual output here is


It can be seen that volatile variables are thread-unsafe . So why is this?

The main reason here is that in the line of code value++, before executing this line of code, the workspace of each thread needs to read the value of the value. At this moment, the value of each thread is the same. When adding an operation, some threads may execute faster, and some may execute slowly. When the operation is executed slowly, the value of the value may change.

Therefore, when we use the volatile key value, we also need to use the synchronized key value and the class under the concurrent package to ensure atomic operations.

Second, disable instruction reordering optimization. The reordering here means that under the premise of correct results, or under the premise of ensuring dependencies, the CPU uses multiple instructions to execute and distribute them to each circuit unit for processing without executing them in program order.

For the 8 rules in the previous section, the volatile keyword has the following rules:

There is a load operation to have a use job, and the reverse is also true. It must appear together in succession, which ensures that the thread of the class obtains the latest value from the main memory, that is, the visible line of volatile

There is an assign action to have a store action, and the reverse is also true. It must appear together here in succession.

And the last one is the order in which the actions are executed. This guarantees to suppress instruction reordering issues.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325721886&siteId=291194637