volatile 关键字的含义

1.一句代码就可以搞定volatile是什么含义:

volatile boolean done = false;
while(!done){
	dosomething();
}

如上只有在状态控制线程自己对done修改,而其他线程只是读取时;才有想要的效果;

2.下面开始稍微解释,物理背景:

由于CPU 内存的速率的巨大差异,CPU直接操作的那些句柄不是直接从内存里面直接读写操作的,而是存在类似于cache 这样的部件来缓和速率差异。例如i++这样一个简单的操作是分为三步进行的:

  1. CPU 发送指令 从 L1 cache load i 到 寄存器;
  2. 寄存器的 i+1;
  3. 寄存器的i 写入到L1 cache;

3.volatile的含义在于(MESI协议):

  1. 当一个Core对缓存中的变量进行write时,其他的Core的缓存控制器会监听到这个写操作,会将自己的相应的缓存行设置为invalid;//这一块协议是物理电路实现的
  2. 当在其它Core在对自己的缓存行进行读写这个变量时,发现自己L1cache缓存中的该变量的缓存行是无效的,那么它就会从其他的核心的cache中或者主存读取数据然后赋值到缓存,然后再对缓存进行读写;
  3. 每次Core对变量的操作,都要从cache中读取;

4.下面举个例子来解释:

4.1如下代码:

public class Test {
    static volatile int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Runnable target = new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<100000;i++){
                    count++;
                }
            }
        };

        Thread t1 = new Thread(target);
        Thread t2 = new Thread(target);
        t1.start();
        t2.start();
        Thread.currentThread().sleep(1000);
        System.out.println(count);//一般不是100000*2
    }
}

4.2 程序执行的模拟:

  1. t1 加载count到自己的L1cache;
  2. t2 发现自己要加载的变量时可缓存的,那么会从其他的核心的L1cache把这一行数据同步过来;
  3. t1 在自己寄存器完成+1操作,counttmp1 = 1,同时t2也完成了+1操作counttmp2 = 1;
  4. t1 写counttmp1到L1cache此时t1的count=1,同时t2的缓存控制器监听CPU总线会监听到修改,会将自己的缓存行设置为invalid;
  5. t2在把counttmp2写到缓存时,发现自己缓存行无效,会同同步t1的cache过来;
  6. 然后把counttmp2 赋值给count,此时t2的count=1;

好了,问题就出在t2的直接写缓存上【count=1】;但是我们期望的是count=2;

这就可以解释被volatile修饰的i,在多线程进行++操作最终结果并不是我们想要的结果了;

转载于:https://my.oschina.net/Aruforce/blog/1843394

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值