栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

volatile关键字的理解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

volatile关键字的理解

volatile关键字的理解

volatile主要为了解决线程间变量的可见性问题,当某个线程修改公共变量时,该变量可以及时通过总线更新到使用这个变量的其它线程副本当中,每个线程都有自己的缓存副本,线程开始运行时就将数据读入到工作副本中。

加了volatile之后,底层的汇编指令会加个lock指令(相当于实现了一种内存屏障),lock指令可以基于总线锁或者缓存锁的机制来达到可见性的一个效果。这里面就涉及到缓存锁以及缓存一致性协议MESI,缓存锁的核心机制是基于缓存一致性协议来实现的,一个处理器的缓存会写到内存会导致其他处理器的缓存无效。

MESI协议存在的问题:就是各个CPU缓存行的状态是通过消息传递来进行的。如果CPU0要对一个在缓存中共享的变量进行写入,首先需要发送一个失效的消息给到其他缓存了该数据的 CPU。并且要等到他们的确认回执。CPU0在这段时间内都会处于阻塞状态。为了避免阻塞带来的资源浪费。CPU中又引入了store bufferes:

如上图,CPU0 只需要在写入共享数据时,直接把数据写入到 store bufferes中,同时发送invalidate消息,然后继续去处理其他指令(异步) 当收到其他所有 CPU 发送了invalidate acknowledge消息时,再将store bufferes中的数据数据存储至缓存行中,最后再从缓存行同步到主内存。但是这种优化就会引起指令重排序行为。例:

package com.zwx.concurrent;
public class ReSortDemo {
    int value;
    boolean isFinish;    void cpu0(){
        value = 10;//S->I状态,将value写入store bufferes,通知其他CPU当前value的缓存失效
        isFinish=true;//E状态
    }
    void cpu1(){
        if (isFinish){//true
            System.out.println(value == 10);//可能为false
        }
    }
}

这时候理论上当isFinish为true时,value也要等于10,然而由于当value修改为10之后,发送消息通知其他CPU还没有收到响应时,当前CPU0继续执行了isFinish=true,所以就可能存在isFinish为true时,而value并不等于10的问题。

故而此时故而CPU层面就提供了内存屏障(Memory Barrier,Intel称之为 Memory Fence),使得软件层面可以决定在适当的地方来插入内存屏障来禁止指令重排序。

CPU内存屏障主要分为以下三类:

  1. 写屏障(Store Memory Barrier):告诉处理器在写屏障之前的所有已经存储在存储缓存(store bufferes)中的数据同步到主内存,简单来说就是使得写屏障之前的指令的结果对写屏障之后的读或者写是可见的。
  2. 读屏障(Load Memory Barrier):处理器在读屏障之后的读操作,都在读屏障之后执行。配合写屏障,使得写屏障之前的内存更新对于读屏障之后的读操作是可见的。
  3. 全屏障(Full Memory Barrier):确保屏障前的内存读写操作的结果提交到内存之后,再执行屏障后的读写操作。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/338248.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号