在讨论之前必须先搞清四种存储介质:寄存器、高级缓存、RAM和ROM。

RAM与ROM大家都比较熟悉了,可以看成是我们经常说的内存与硬盘,寄存器属于处理器里面的一部分,而高级缓存cache是CPU设计者为提高性能引入的一个缓存,也可以说是属于处理器的一部分。在利用CPU进行运算时必定涉及操作数的读取,假如CPU直接读取ROM,那么这个读取速度简直是无法忍受的,于是引入了内存RAM,这样做确实让速度提高了很多,但由于CPU发展十分迅猛而另一方面RAM的发展受到技术及成本的限制发展缓慢,此时产生了一个很难调和的矛盾,CPU运算速度比从RAM读取数据的速度快了几个数量级,木桶原理我们都很熟悉了,桶的容量大小取决于最短的那块,这必将影响处理器的效率,于是又引入了高级缓存,直接在CPU添加了几个级别的缓存,他们的速度虽然无法与寄存器比较,但是速度已经提升很多,基本能跟CPU的计算速度相匹配。总结成一句话就是,为了解决CPU运算速度与读取速度的矛盾,引入了多级存储机制。

如图所示,机器的四种存储介质是有关系的,一般程序运行时会将ROM相关的程序数据都读进RAM中,而需要运算的数据或运算过程中即将要用到的数据则会被读进高速缓存或寄存器中,假如要进行的运算所需要的所有数据及指令都在寄存器和高速缓存中,则这个运算过程则表现得非常平坦,并不存在性能瓶颈,因为运算速度跟读取速度基本匹配了。读取速度快慢的排序如下:寄存器>cache>RAM>ROM,用一个比较好理解但不完全正确的概念来解释,因为寄存器是离CPU最近的,所以读取最快,高速缓存次之,RAM第三,ROM离得最远,自然速度最慢(当然不能完全用距离来说明这个问题,但用距离是比较好理解的,另外的还因为这些存储介质的硬件设计不同、工作方式不同)。从另一个角度来看,CPU读取数据的顺序是先尝试读寄存器,如果不存在则尝试读高速缓存,如果还不存在则读RAM,最后才是读ROM。一些CPU有三级cache,读取时是一级一级往下直到找到需要的操作数,一般做的比较好的CPU3级缓存已经能让命中率高达95%以上。

有了上面的知识再往下探索就水到渠成了,如果把Java内存模型与多级存储机制类比将发现为了提高性能java引入了工作内存的概念,提高了线程执行时读取数据的速度,这样就可以把java模型中的主存和工作内存分别于RAM和高速缓存或寄存器对应起来,每条线程的工作内存预先把需要的数据复制到高速缓存或寄存器(但是不保证所有的工作内存的变量副本都是放在高速缓存,也可能在RAM,具体的还要看JVM是如何实现的),这样在多线程并发时性能得到保证。当然寄存器和高速缓存由于成本原因存在容量大小限制的问题,这个也是考验JVM实现的一个难题。

一般引入一种机制解决了一个问题,但同时也会带来另外一个问题,数据同步即是带来的另一个问题,即是否能保证当前运算使用的变量值总是当前时刻最新的值。如果变量值并非最新值,将会导致数据的脏读,最终可能导致计算结果大相径庭。这时可能有人会想起java中有个volatile关键词,毫无疑问它能保证可见性,让每个线程得到的都是主存中最新的变量值,但它就足以保证数据的同步性了吗?举个典型例子,伪代码如下:

private volatile int count=0;
private void increase(){count++}
public static void main(String args){创建30条线程执行;每条线程任务都是执行10000次increase()方法;
}

执行完所有线程任务,我们期望的结果会是30*10000,但实际却是一个小于30*10000的数,刚开始看到一定觉得有点奇怪,但仔细一想就清楚了,count++编译后最终并非一个原子操作,它由几个指令一起组合实现。下图能较清晰地说明此点,在Java内存模型中,count++被分割成5个步骤(当然这个并不是确切的指令执行步骤),这5步不具有原子性,假如在完成过程中,其他线程就去读了主存的count变量,那明显导致了一个脏读现象。

导致这个问题的原因其实是因为volatile不具备锁操作,要解决此问题其实不难,就是将这五步变为原子操作,即保证线程一完成之前不能有其他线程读取count变量,对count变量加一个互斥锁即可达到,线程一在执行第①步前对count加锁,其他线程无法对count进行访问,线程一执行完第⑤步后释放锁,此刻开始才允许其他线程获取此变量。

Volatile是一个很容易搞混的关键词,很多经验丰富的开发人员都不能正确使用它,这节从机器结构讲到对应的java内存模型,再引出主存与工作内存之间数据同步的问题,进而更好地解释了volatile的确切含义——它只保证可见性,它不足以保证数据的同步性。

========广告时间========

公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。

鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以购买。感谢各位朋友。

为什么写《Tomcat内核设计剖析》

=========================

欢迎关注:

volatile足以保证数据同步吗相关推荐

  1. Mysql数据库在多服务器集群的情况下如何保证数据同步?

    数据不同步的异常情况通常出现在,在同一时刻有多个写数据的操作发生.因此要避免数据库的数据不同步这个问题,就要避免同时有多个写数据的操作,同时只能有一个写操作. 这在一台服务器运行的时候似乎是没有问题的 ...

  2. 基于 Kafka 与 Debezium 构建实时数据同步

    起源 在进行架构转型与分库分表之前,我们一直采用非常典型的单体应用架构:主服务是一个 Java WebApp,使用 Nginx 并选择 Session Sticky 分发策略做负载均衡和会话保持:背后 ...

  3. elasticsearch 数据类型_基于 MySQL Binlog 的 Elasticsearch 数据同步实践

    来源;马蜂窝 一.背景 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品.订单等数据的多维度检索. 使用 Elasticsearch 存 ...

  4. 基于 MySQL Binlog 的 Elasticsearch 数据同步实践

    一.为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品.订单等数据的多维度检索. 使用 Elasticsearch 存储业务数 ...

  5. 基于 MySQL Binlog 的 Elasticsearch 数据同步实践 原

    一.背景 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品.订单等数据的多维度检索. 使用 Elasticsearch 存储业务数据可以 ...

  6. Android 多线程保证操作同步(同步锁的俩种)

    今天来介绍一下android中多线程同步的机制 首先我们来创建几个多线程,模仿一下文件读写的操作. private void writeLog() {for (int i = 0; i < 3; ...

  7. 微服务之间数据同步的思考

    周末无聊,来一篇服务之间数据同步的博客吧(主要讲注意的问题).具体什么业务场景就不举例了. ps:纯属个人瞎说,有错误.不足请大侠指出.嗯,开始说正事了. 业务流程 主要业务流程如下: #mermai ...

  8. 如何保证elasticsearch和mysql数据库的数据同步?

    在应对大数据量的电商网站时,通常我们把热门数据放在elasticsearch中.但如何保证es和mysql的数据同步? 方法一:.双写模式 1.首先添加商品入数据库,添加商品成功后,商品入ES, 2. ...

  9. mysql只读库的数据同步_mysql只读模式下数据迁移,保证数据一致性

    在MySQL数据库中,在进行数据迁移和从库只读状态设置时,都会涉及到只读状态和Master-slave的设置和关系. 经过实际测试,对于MySQL单实例数据库和master库,如果需要设置为只读状态, ...

最新文章

  1. 搭建linux下eclipse php完美搭建开发php,搭建linux上的Eclipse+PHP编程环境
  2. c语言结构体输入身高体重,c++:输入n名学生的身高体重,按身高排序输出并计算平均体重和身高...
  3. Josephus 问题相关
  4. java 0x0f_Java - 字节 字符
  5. VMware vsphere client报错问题
  6. 图像处理中腐蚀与膨胀的原理
  7. ubuntu设置始终亮屏_ubuntu设置关闭屏幕和锁定
  8. 阿里云企业IPv6部署方案
  9. cratedb导入json文件
  10. php msn,利用php给MSN发送消息
  11. deeplabv3+ 跑 cityscape 数据集
  12. 30行python代码实现豆瓣电影排行爬取
  13. OpenCV视频处理操作
  14. Spring整合Mybatis遇到的错误一
  15. 手机rar压缩包解密,rar压缩包权限密码多少?
  16. 谷歌浏览器扩展程序XDM_这才是谷歌浏览器的正确打开方式,有效节省内存占用,流畅飞起...
  17. jadx反编译—下载和使用(傻瓜教程,非常详细)
  18. upload-labs靶场通关指南(16-17关)
  19. 上海迪士尼将推出虎年新春全新体验
  20. Collection.sort()方法

热门文章

  1. 一个HashMap跟面试官扯了半个小时
  2. emplace_back不能取代push_back的情况
  3. 黑莓手机刷Linux系统
  4. 只懂python一门编程语言的人,可以做计算机视觉工程师吗?
  5. 【二级等保】二级等保安全物理环境要求有哪些?
  6. 提高网站权重,快速增加百度收录量
  7. opendolphin_认床的你也许拥有海豚般的睡眠
  8. Windows实验——DNS劫持演练
  9. 服务器虚拟机的c盘怎么加,xp虚拟机c盘怎么扩容
  10. Linux文件打包与解压缩