volatile与内存可见性

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzx_longyou/article/details/55101653

    在多线程环境下,对共享变量的操作,往往会遇到内存可见性问题。先看下面一段代码:

public class TestVoltatile {
    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();

        while (true) {
            if (td.isFlag()) {
                System.out.println("------------------");
                break;
            }
        }
    }
}

class ThreadDemo implements Runnable {
    private boolean flag = false;

    public void run() {


        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        flag = true;

        System.out.println("flag=" + isFlag());
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
    这段你代码中,有两个线程,一个是main线程,一个是自己创建的线程(以下称为Thread-0)。其中Thread-0线程的run方法中去修改flag的值,main线程死循环判断flag的值如果为true则退出循环。运行上面的代码,发现 Thread-0线程输出flag=true,但是程序却没有停止。

    这个问题涉及到了flag变量的内存可见性问题。每个线程在执行中都有一块缓存区,flag变量是类的属性,在堆中分配空间。当Thread-0线程要对flag的值进行修改的时候,会先到堆内存中读取flag的值到自己的线程缓存中,然后修改其值。修改之后,还没来得及将其写入到堆内存中,main线程在循环中判断isFlag()的时候就把堆中的flag值读到了自己的缓存中,此时为false。由于while(true)循环在jvm底层有做了优化,所以每次循环判断的falg值是main线程缓存中的,一直都是false。所以导致了flag值被修改后,main线程还是没有停止下来,一直在死循环。这就是内存可见性问题。

    解决这个问题我们可以使用同步,使用synchronized同步代码块将if包围起来,这样每次都能刷新缓存,取到最新的flag值。但是使用锁会导致性能的下降,多线程就会出现等锁的情况。

    还有一个解决方式就是使用volatile关键字修饰flag变量。被volatile修饰的变量,在每次使用时,都会到内存中去取最新的值,这就解决了多线程间内存可见性的问题,当多个线程进行操作共享数据时,可以保证内存中的数据可见。volatile不同于synchronized,volatile不具备”互斥性”,即多个线程可以同时访问,不需要抢锁。并且,volatile不能保证变量的"原子性"。

    解决方式一:

    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();

        while (true) {
            synchronized (td) {
                if (td.isFlag()) {
                    System.out.println("------------------");
                    break;
                }
            }
        }
    }

    解决方式二:

    private volatile boolean flag = false;


内存可见性问题还可参考一下博客:

http://blog.csdn.net/beiyetengqing/article/details/49583381

http://www.cnblogs.com/frydsh/p/5720658.html

http://www.cnblogs.com/longshiyVip/p/5211476.html





猜你喜欢

转载自blog.csdn.net/lzx_longyou/article/details/55101653