java volatile 实现变量可见性

java volatile 实现变量可见性

volatile 本意是易变的,多变的,用来解决变量可见性问题,什么是变量可见性问题?先看一下变量在计算机内部第一次加载和写入过程:

此时,内存和寄存器中v都是101,再进行计算时时直接从register中读取而不是memroy来提高速度。这在单核CPU中没毛病,如果是多核CPU中,变量v在各自寄存器中都有值了,即使内存中的变量v更新了它还是从寄存器的缓存中读取,就会导致程序运行结果不符合预期,变量的可见性,指的是它被修改后其他线程可以立即看到最新结果的能力。使用一个用例来复现这种现象:

  1. 创建一个全局变量running
  2. 创建一个名为ObserveThread子线程,让它不停观察running的值(预期它在不停地从寄存器中读值)
  3. 在主线程中修改running的值,观察子线程/和主线程中的值是否发生变化(预期子线程的没变,主线程的变了)

代码:

package juc.test.sharememroy;

public class StaticVolatileTest {

    static /*volatile*/ boolean running = true;

    public static void main(String[] args) {

        new Thread("ObserveThread"){
            @Override
            public void run() {
                System.out.println("thread start");
                while (running){}
                System.out.println("thread end");
            }
        }.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        running = false;
        System.out.println("main thread end, running = " + running);
    }   
}

3秒后线程没有结束,查看JVM中的线程状态发现ObserveThread还在Running:

控制台输出结果:

thread start
main thread end, running = false

可以说明ObserverThread 线程没读取到主线程修改后的值,而是从它的缓存中读值,只要将

static /*volatile*/ boolean running = true;

修改为:

static volatile boolean running = true;

问题就解决了,输出就变成:

thread start
main thread end, running = false
thread end

volatile是使用缓存一致性协议实现的,对于可能频繁修改的变量,每次不从寄存器而是从内存中读取,降低速度来保证可见性。

posted @ 2020-08-02 11:11  oaksharks  阅读(392)  评论(0编辑  收藏  举报