Java 内存模型到volatile关键字

前言

让计算机同时去做几件事不仅仅是计算机的运行能力增强了,还有一个重要原因是计算机的运行速度与它的存储以及通讯子系统速度差距巨大,大量的时间都耗费在 I/O 、通讯上,以至于处理器大部分时间都处于等待其他资源准备上。由于计算机的存储于处理机有几个数量级上的差距,因此现代计算均加入了一层读写速度尽量接近处理速度的高速缓存(Cache)作为内存与处理器之间的缓存,当运算时,先将数据复制到缓存中,处理器从缓存中读取数据处理,当处理结束的时候,再从缓存中同步数据到内存中,这样处理器就无需等待缓存的内存 I/O。这样会引起一个问题:数据不同步,即每个处理器都有自己的高速缓存,但是又公用一份主存,那么同步到内存中的数据是以哪一个处理的高速缓存为准呢?

Java 内存模型(JMM)

Java 内存模型规定了所有的变量都存储在主内存中,每条线程都有自己的工作内存,工作内存内的变量数据为主内存中数据的一份拷贝,线程只能读写工作内存中的数据,不同线程的工作内存不能相互访问,线程之间的数据传递需要通过主内存。

volatile变量

volatile关键字是 Java 虚拟机中提供的最轻量级的同步机制。当一个变量被volatile修饰之后,它具备两个特性:

    1.保证了此变量对所有线程可见性;

每次线程对volatile修饰的变量的读都是直接从主内存中取出(而非从工作内存中读出),修改完变量之后直接将修改过后的值写入主内存。

对于其它线程来说是可见的,即线程每次获取volatile变量的值都是最新的。

    2.禁止指令重排序优化。指令重排序会干预程序的并发执行。

volatile使用场景

volatile变量修改不依赖当前值,如:a++,a+=x….,

public class VolatileTest{

    privatevolatile int a = 0;

    public setA(){

    a++;

    }

}

VolatileTest test = new  VolatileTest();

当有100个线程对test对象进行操作时,则会出现问题。

当某个线程把 test 对象 的值取到操作栈顶时,volatile保证了 a 值此时此刻是正确的,但是执行 setA() 的时候,其他指令可能已经执行了setA(),此时 a 的数据就为过期数据,如果再将数据写入,怎会出现数据不一致问题。

volatile与 static 关键字

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。

被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。

对于 static 修饰变变量,读操作会优先读取工作内存的数据,如果工作内存中不存在,则从主内存中拷贝一份数据到工作内存中;写操作只会修改工作内存的副本数据,这种情况下,其它线程就无法读取变量的最新值。修改过后的只也不知道什么时候会写入内存中,因此无法保证数据一致性

参考文献:

http://www.importnew.com/27863.html

https://www.jianshu.com/p/195ae7c77afe

你可能感兴趣的:(Java 内存模型到volatile关键字)