Java关键字volatile的解释

发布时间 2023-07-20 17:03:18作者: Euler0525

来源:https://dzone.com/articles/java-volatile-keyword-0

实验过程

实验程序如下:

public class VolatileTest
{
    private static volatile int COUNTER = 0;

    public static void main(String[] args)
    {
        new ChangeListener().start();
        new ChangeMaker().start();
    }

    /**
     * 监听 COUNTER, 如果 COUNTER 变化, 输出 COUNTER 的值,
     * 直到 COUNTER达到 5.
     */
    static class ChangeListener extends Thread
    {
        @Override
        public void run()
        {
            int threadValue = COUNTER;
            while (threadValue < 5)
            {
                if (threadValue != COUNTER)
                {
                    System.out.println("Got Change for COUNTER : " + COUNTER);
                    threadValue = COUNTER;
                }
            }
        }
    }

    /**
     * 每隔 500ms COUNTER 自增 1,
     * 直到 COUNTER 达到 5.
     */
    static class ChangeMaker extends Thread
    {
        @Override
        public void run()
        {
            int threadValue = COUNTER;
            while (COUNTER < 5)
            {
                System.out.println("Incrementing COUNTER to : " + (threadValue + 1));
                COUNTER = ++threadValue;
                try
                {
                    Thread.sleep(500);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

程序中定义了一个volatile修饰的int变量COUNTER。然后,定义了两个单独的线程,分别为ChangeListenerChangeMaker

  • ChangeListener:监听COUNTER,如果发生变化,输出COUNTER的值,直到COUNTER达到\(5\)
  • ChangeMaker:每隔\(500ms\) COUNTER自增\(1\),直到COUNTER达到\(5\)

main函数中,分别启动这两个线程,观察程序输出结果:

Incrementing COUNTER to : 1
Got Change for COUNTER : 1
Incrementing COUNTER to : 2
Got Change for COUNTER : 2
Incrementing COUNTER to : 3
Got Change for COUNTER : 3
Incrementing COUNTER to : 4
Got Change for COUNTER : 4
Incrementing COUNTER to : 5
Got Change for COUNTER : 5

Process finished with exit code 0

去掉修饰COUNTERvolatile,输出结果:

Incrementing COUNTER to : 1
Incrementing COUNTER to : 2
Incrementing COUNTER to : 3
Incrementing COUNTER to : 4
Incrementing COUNTER to : 5

此时让ChangeListener在循环中等待5ms,输出结果:

Incrementing COUNTER to : 1
Got Change for COUNTER : 1
Incrementing COUNTER to : 2
Got Change for COUNTER : 2
Incrementing COUNTER to : 3
Got Change for COUNTER : 3
Incrementing COUNTER to : 4
Got Change for COUNTER : 4
Incrementing COUNTER to : 5
Got Change for COUNTER : 5

Process finished with exit code 0

解释

volatile关键字会确保我们对变量的读写都同步到主内存里,而不是从 Cache 里面读取。

  • 使用volatile关键字时,两个线程的输出结果相同;

  • 去掉volatile关键字后,ChangeListener是一个忙等待的循环,他不断地从线程的Cache中获取COUNTER的值,于是,这个线程就没有时间从主内存里面同步更新后的COUNTER,就会已知卡在COUNTER=0的循环中;

  • 让循环等待\(5ms\),让线程有机会把最新的数据从主内存同步到Cache中,于是ChangeListener就能监听到ChangeMakerCOUNTER变量的修改。