volatile可见性

问题描述

我在学习volatile的时候,知道它的作用是保证线程的可见性,意思是说当共享变量发生改变时,其它线程可以见。但我不明白其它线程可见是什么意思? 例如共享变量x=0加了volatile这个关键字; A,B两个线程 A读到x=0; B也读到x=0; A做了加一操作,此时x=1。那么B线程也应该知道x=1; 可是B做加一操作时,x也等于1。 那么我想知道这个B线程知道了x已经改变是什么意思?最好有个volatile例子能说明下。 我突然想到是这个可能: 因为x=x+1不是原子操作,分二个步骤,加操作和赋值操作。 当B的加操作比A线程快一步,但B的赋值操作比A线程慢一步时 B已经用0做完了加操作得到的结果是1,但是没赋值给x。 A已经做完了加操作,x值此时已经更新到主内存中。 按照可见性,B重新读取x=1。此时B线程内x=1,是从主内存中更新的。 再做赋值操作把B线程做的加操作结果赋值给x,x=1。 所以出现2个1。 不知道我突然想出的步骤是不是正确的,希望大家指导。 问题补充: 我在学习volatile的时候,知道它的作用是保证线程的可见性,意思是说当共享变量发生改变时,其它线程可以见。但我不明白其它线程可见是什么意思? 例如共享变量x=0加了volatile这个关键字; A,B两个线程 A读到x=0; B也读到x=0; A做了加一操作,此时x=1。那么B线程也应该知道x=1; 可是B做加一操作时,x也等于1。 那么我想知道这个B线程知道了x已经改变是什么意思?最好有个volatile例子能说明下。 我突然想到是这个可能: 因为x=x+1不是原子操作,分二个步骤,加操作和赋值操作。 当B的加操作比A线程快一步,但B的赋值操作比A线程慢一步时 B已经用0做完了加操作得到的结果是1,但是没赋值给x。 A已经做完了加操作,x值此时已经更新到主内存中。 按照可见性,B重新读取x=1。此时B线程内x=1,是从主内存中更新的。 再做赋值操作把B线程做的加操作结果赋值给x,x=1。 所以出现2个1。 不知道我突然想出的步骤是不是正确的,希望大家指导。

解决方案

你自己回答到了x=x+1确实不是原子操作所以可能出现两个1x++,++x等都不是原子操作
解决方案二:
不加volatile A加1 B可能读到的还是0,这在高并发情况下会出现。因为有可能会去读一级二级缓存。volatile使编译器产生的汇编指令, 仅仅从主存操作数据.这样就保证每次都是最新的数据不存在缓存数据。但是不能保证线程间同步,也就是说A加1跟B加1可能同时发生,也就是x+1这个操作可能被多个线程同时执行。这个是volatile不能保证的。
解决方案三:
A做了加一操作,此时x=1。那么B线程也应该知道x=1; B知道是有时间间隔的,因为线程间的内存需要先同步到主内存,再同步到其他各个线程的内存上的,这些操作虽然很快,但在多线程下还是有时间 间隔的
解决方案四:
当然要是想深入些可以看看这篇http://www.ibm.com/developerworks/cn/java/j-jtp02244/
解决方案五:
这个跟JAVA的内存模型关系比较大每个线程都有自己的内存一个共享变量(没有被VOLATILE修饰时),主内存,A线程内存,B线程内存都会有一份的(他们之间的同步由虚拟机处理,并且需要消耗时间 ,假设这里有A,B两个线程)如果被VOLATILE修饰后,这个共享变量就只在主内存,而A线程和B线程内存都不会存放这个共享变量,所以当A线程修改变量时直接操作主内存,B线程读变量时也直接操作主内存,这样B就可以第一时间 知道变量发生变化了你可以看看这篇文章 http://jiangzhengjun.iteye.com/blog/652532

时间: 2024-10-30 03:35:17

volatile可见性的相关文章

singleton-求助:单例模式下volatile可见性问题

问题描述 求助:单例模式下volatile可见性问题 public class Singleton { private volatile static Singleton instance = null; private Singleton() { } /** * @return */ public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (insta

Java并发——volatile的原理

volatile关键字就是Java中提供的另一种解决可见性和有序性问题的方案.对于原子性,需要强调一点,也是大家容易误解的一点:对volatile变量的单次读/写操作可以保证原子性的,如long和double类型变量,但是并不能保证i++这种操作的原子性,因为本质上i++是读.写两次操作. 1 volatile的原理 1.1 可见性 在前文中已经提及过,线程本身并不直接与主内存进行数据的交互,而是通过线程的工作内存来完成相应的操作.这也是导致线程间数据不可见的本质原因.因此要实现volatile

单例模式和双重检测的小结

设计模式的经典模式之一--单例模式 这个也是面试经常被问起的面试,一般都要求手写 [饿汉模式]非延时加载 --以空间换时间 [懒汉模式]延时加载--以时间换空间 看似简单,但是在懒汉模式还隐藏了一个双重检测,其中还是涉及到JVM内存的"无序写入"问题(后面使用的 volatile ) 1.饿汉模式 比较简单,非延时加载,一上来就把对象给new出来了 [java] view plain copy <span style="font-family:Microsoft YaH

关于 volatile 修饰在数组上的可见性问题

问题描述 使用volatile修饰符时,大家都知道被它修饰的属性都有可见性的特性,如果将volatile修饰在数组上,按我的理解是:它只对引用这个数组的属性本身有效,而对这个数组里面引用的对象,是没有效果的.但是现在问题来了,我在做试验时,发现在它对数组里面引用的对象也有效果,我的代码如下,大家帮忙看看是什么原因.代码一:publicclassTest{privateStringname;publicTest(Stringname){this.name=name;}publicStringget

volatile是否能保证数组中元素的可见性?

在javaeye有位朋友问了我一个非常好的问题. 问题 一个线程向volatile的数组中设置值,而另一个线程向volatile的数组中读取. 比如seg.setValue(2),随后另一个线程调用seg.getValue(2),前一个线程设置的值对读取的线程是可见的吗? 我看书上说volatile的数组只针对数组的引用具有volatile的语义,而不是它的元素. ConcurrentHashMap中也有这样的代码,我很疑惑,希望得到你的解答,谢谢. 查看源代码 打印帮助 01 public c

聊聊并发(一)深入分析Volatile的实现原理

本文属于作者原创,原文发表于InfoQ:http://www.infoq.com/cn/articles/ftf-java-volatile 引言 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的"可见性".可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值.它在某些情况下比synchronized的开销更小,本文将深入分析在硬件层面上Inter

深入理解Java内存模型(四) volatile

volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解 volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这些单个 读/写操作做了同步.下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { volatile long vl = 0L; //使用volatile声明64位的long型变量 public void set(long l) { vl

Java多线程基础总结三: volatile

前面的两篇总结简单的说明了同步的一些问题,在使用基础的同步机制中还有两个可以分享的技术:volatile关键字和ThreadLocal.合 理的根据场景利用这些技术,可以有效的提高并发的性能,下面尝试结合自己的理解叙述这部分的内容,应该会有理解的偏差,我也会尽量 的在完善自己理解的同时同步更新文章的错误. 或许在知道synchronized配和对象内部锁的机制以后,可以提高写出正确同步的并发程序成功率,但是这时候会遇到另一个大问题:性 能!是的,对于 synchronized带来的可能庞大的性能

show一下java中的volatile的作用

具体作用就不多讲了,大概就是保证可见性和防止重排序. 其实很早前就知道有这个关键字,试过很多次,总觉得加了和没加效果一样. 这次终于在阅读<java并发程序实践>(顺便义务广告一下,好书)的时候有了灵感,写了一段很普通的代码: Java代码 public class NoVisibility { private boolean ready=false; int num; private class ReaderThread extends Thread { public void run()