Volatile可见性探讨

一、volatile的两个作用

  1. 在多处理器开发中保证了共享变量的可见性。(当一个线程修改共享变量的值时,会将值写回内存,另一个线程读该变量时,会从主存中读取,而不是cpu缓存)。
  2. 禁止指令重排序。

二、用volatile和不用volatile的区别

见一个例子:

public class VolatileTest {

    private long a = 1;

    private volatile long b = 1;

    private Thread mThread1 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                if (a == 1) {
                    a = 2;
                    System.out.println("a = 2");
                }
//                if (b == 1) {
//                    b = 2;
//                    System.out.println("b = 2");
//                }
            }
        }
    });
    private Thread mThread2 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                if (a == 2) {
                    a = 1;
                    System.out.println("a = 1");
                }
//                if (b == 2) {
//                    b = 1;
//                    System.out.println("b = 1");
//                }
            }
        }
    });

    public void test() {
        mThread1.start();
        mThread2.start();
    }

    public static void main(String[] args) {
        VolatileTest volatileTest = new VolatileTest();
        volatileTest.test();
    }
}

运行上述代码会发现,只对a进行修改,程序不一会就不打印值,但程序还在运行;只对b进行修改,程序就会一直打印值;同时对a和b进行修改,程序也会一直打印值。
现象分析

  1. 不用volatile修饰,即只对a修改的情况。cpu在读取a的值时,会首先从主存中找,因此一开始也会打印值,然后很快,它会从CPU缓存中找,缓存的中的数据是自己写进去的,因此之后就会一直判断不通过,就不会再打印值了。
  2. 用volatile修饰,即只对b修改的情况。cpu读取b的值时,会直接去主存找,因此,其他线程对b的修改,当前线程读取时会获取更新的值。
  3. 按道理说,如果同时对a和b修改,应该是一段时间后不打印a的值,但会一直打印b的值。实际上a和b的值都会打印。(这里可能的解释是:用volatile修饰的变量会使其对应的整个cpu缓存行失效,这里有可能是a和b在一个缓存行中,导致如果对b修改,那么对a的读取也是从主存中读。)
  4. 补充一点,System.out.println()会导致线程本地缓存失效,即影响内存可见性,下一次读会从主存中读。第1点中,有输出语句,那为什么对a值的修改未体现可见性?考虑第一个线程,判断通过后,会对a值修改,此时a值为2,下一次读取是从主存中读取,判断不通过,但是本地线程又开始缓存a的值,本地缓存a的值为2,下一次就是从缓存中读取了。虽然线程1和2是并发的,但总有一段时间,线程1会执行多个循环,导致线程1的本地缓存会缓存自己修改的值。线程2也是类似的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值