1.如果是CPU缓存,多核CPU之间存在“缓存一致性”协议,所以这里并不会导致“不可见”的问题; 2.如果是CPU Store Buffer,因为容量有限,迟早会写回到缓存,所以这里并不会导致“永远不可见”的问题; 3.如果是CPU指令重排序,由于这段代码是在一个循环中读取变量的值,所以这里不会有任何影响。 那么,问题就只能出在J...
1.如果是CPU缓存,多核CPU之间存在“缓存一致性”协议,所以这里并不会导致“不可见”的问题; 2.如果是CPU Store Buffer,因为容量有限,迟早会写回到缓存,所以这里并不会导致“永远不可见”的问题; 3.如果是CPU指令重排序,由于这段代码是在一个循环中读取变量的值,所以这里不会有任何影响。 那么,问题就只能出在J...
这个现象就是在多核CPU多线程编程环境下会出现的可见性问题。 Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程在工作内存中保存的值是主内存中值的副本,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。等到线程对变量操作完毕之后会将变量的最新值刷新回到主内存。
如上篇中利用双重检索单例一下,可以使用 volatile static Singleton instance 解决 instance 的可见性和有序性问题。 例如下面的示例代码,假设线程 A 执行 writer() 方法,按照 volatile 语义,会把变量 “v=true” 写入内存;假设线程 B 执行 reader() 方法,同样按照 volatile 语义,线程 B 会从内存中读取变量 v,...
这些问题可能会在你不经意间发生,导致难以预料的结果。 数据可见性:可见性是指当一个线程修改了共享变量的值,其他线程能够立即看到修改的值。在并发环境中,由于线程的内存缓存(cache)和优化,可能会导致一个线程修改了数据,但是其他线程看到的还是旧的值。要解决可见性问题,可以使用 Java 的 volatile 关键字。
可见性问题的原因: 可见性的原因,是因为java内存模型中,主内存的数据需要在工作内存中有副本,才能被工作线程使用。如下图所示: 主内存与工作内存与线程 如数据a,在两个线程中使用,即是在两个工作内存中存在a数据的副本,其中一个修改了a,只是在工作内存中修改,修改后的数据何时同步到主内存,同步到另一个工作内存...
JMM(java memory model)是java语言规范中定义的java内存模型,用于规范并发线程间共享内存的可见性问题。由于不同机器的硬件设备不同、cpu优化重排的方式不同,因此为了解决跨平台过程中的内存可见性问题,抽象出JMM概念,以屏蔽平台差异。 JMM中抽象出两种内存模型,线程独有的本地内存和线程间共享的主内存。本地内存是一...
Java并发之volatile关键字内存可见性问题 线程之间数据共享案例 我们先来看一个场景:Main函数启动后,调用一个线程向list中添加数据。List的size为5的时候,设置变量flag为true.然后,主线程根据flag的值进行其他操作。代码如下:编辑 运行结果:我们发现,当子线程输出flag为ture后,主线程也没有输出===。这是为什么...
可见性问题是一个综合性问题。除上面提到的缓存优化或者硬件优化(有些内存读写可能不会立即触发,而会先进入一个硬件队列等待)会导致可见性问题,指令重排(这个问题将在下一节中详细讨论)及编辑器的优化,也有可能导致一个线程的修改不会立即被其他线程察觉。下面来看一个简单的例子:Thread 1 Thread 21: r2 =...
CPU 增加了缓存,均衡和内存的速度差异 发明了进程、线程,分时复用 CPU,提高 CPU 的使用效率 编译指令优化,更好的利用缓存 三种解决办法虽然有效,但是也带来了另外的三个问题,分别就是并发 bug 产生的源头。 1.可见性问题 如果是单核 CPU,多个线程操作的都是同一个 CPU 缓存,那么一个线程修改了共享变量,另一个...