volatile足以保证数据同步吗

在讨论之前必须先搞清四种存储介质:寄存器、高级缓存、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的确切含义——它只保证可见性,它不足以保证数据的同步性。

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

鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以到 https://item.jd.com/12185360.html 进行预定。感谢各位朋友。

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

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

欢迎关注:

时间: 2024-10-30 02:59:06

volatile足以保证数据同步吗的相关文章

如何为goldengate的数据库中保证数据同步的情况下为表加列

问题描述 如何为goldengate的数据库中保证数据同步的情况下为表加列 数据库现在做GOLDENGATE,DML同步了部分表,现在在source端,需要同步的表中加一列,在target表中也加一列,该如何操作才能保证加列的过程中数据同步且不丢失

高手指教下,怎样安全生成静态的页面,并且保证数据同步.

问题描述 很久很久以前CSDN的帖子是XML格式的.它的数据具体是存成了*.xml文件,还是请求时生成的?现在全弄成静态页面.而且在提交的时候不刷新增加到当前页面.(不要空讲用Ajax,主要是,提交后它怎样存储资料,怎样保证资料操作时的异常处理.)另外在Blog中我发现,一旦网络不畅通的情况下,发送的回帖,并没有回显在我的页面上,刷新也看不见,但是,如果我再继续跟一帖,那么我现在发送的回复能看见,并且以前回复的那些也一起全部显示出来了.这是不是异步操作不完全的结果?比如讲,是不是:服务端保存了数

银行取款[多线程]{使用volatile修饰共享变量,但此场景并不保证线程同步}

经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题. 此处用多线程实现,同时取款的模拟实现,使用volatile修饰共享变量,但此场景并不保证线程同步,查看取款安全隐患问题,代码如下: 我学习地址(Thanks for auther): Java 理论与实践: 正确使用 Volatile 变量 java中volatile关键字的含义 ----------------------------------------------------------

jvm-哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话

问题描述 哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话 哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话 哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话 哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话 解决方案 简单来说,volatile在多cpu环境下不能保证其它cpu的缓存同步刷新,因此无法保证原子性. 解决方案二: 还是以最常用的i++来说吧,包含3个步骤 1,从内存读取

线程-java缓存数据同步问题

问题描述 java缓存数据同步问题 最近在做一个简单的java缓存,线程的主要功能是:查询缓存中是否存在该值,存在则返回,不存在则计算,计算完了将该键值对放到Cache里面.但是这里有个数据同步的问题,可能会有重复计算.即线程1发现不存在该值,去计算,线程2访问同一数据随后也发现不存在该值,去计算.这样就会出现重复计算,请问有没啥办法避免.谢谢大家了! public void run() { Long result = null; InputMsg msg = new InputMsg(num,

Windows下多线程数据同步互斥的有关知识

 对于操作系统而言,在并行程序设计中难免会遇到数据同步和共享的问题,本文针对这个问题,以windows系统为例回顾一下资源同步的相关问题.要点如下: 1.同步和数据共享  数据征用 2.同步原语     1.互斥和临界区     2.自旋锁     3.信号量     4.读写锁     5.屏障     6.原子操作与无锁代码 3.进程和进程间通信     1.共享内存和映射文件     2.条件变量     3.信号和事件     4.消息队列     5.命名管道     6.sock

Ubuntu Server Rsync服务端与Windows cwRsync客户端实现数据同步配置教程

1.Rsync服务端 系统:Ubuntu Server 11.10 IP地址:192.168.21.168 数据存放目录:/home/mysql_data2.cwRsync客户端 系统:Windows Server 2003 IP地址:192.168.21.130 同步的目录:D:mysql_data实现目的:cwRsync客户端每天凌晨3:00钟自动同步Rsync服务端/home/mysql_data目录中的数据到D:mysql_data目录系统运维 温馨提醒:qihang01原创内容版权所有

MySQL异构数据同步--tair为例

在实现levelDB挂载成MySQL引擎时,发现在实际存储是key-value格式时候,MySQL的异构数据同步,可以更简单和更通用. 以tair为例,简要描述一下以MySQL为基础的一种方案. 所谓异构数据同步,是指应用只更新MySQL,而由后端的某些机制将这些更新应用到其他数据存储服务上. 1.MySQL-Tair 引擎 a) 使用 b) 说明 这不是一个"存储引擎",实际上数据存储在tair服务器上.执行insert/update/delete时,只是将对应的动作put /rem

两台SqlServer数据同步解决方案

server|sqlserver|解决|数据|数据同步 前些天遇到特殊需求,两台SqlServer服务器天隔一方,需要实效性很高的数据同步.     大家知道通过internet网,要高准确性和高实效性的实现两台数据库数据同步是个棘手的问题.     网络上找了些资料,有一篇文章可供参考http://www.sxsoft.com/technology_test/show_news.asp?id=450,文章中介绍了Sqlserver的出版和订阅方法来同步数据.根据文章做了下试验,是可以的,有以下