Java的内存模型(JMM)规定了所有的变量都是存在于 主内存(RAM)
当中的,而每个线程都有自己的工作内存或者本地内存
,线程对变量的所有操作都必须在自己的工作内存
中进行,而不能直接对主内存
操作,并且每个线程都不能访问其他线程
的工作内存或者本地内存
。
比如,在某个线程中对变量 i
的复制操作 i=1
,改线程必须在本地内存中对 i
进行修改之后才能将其写入 主内存
之中。
Java内存模型(JMM)三大特性
一、原子性
所有操作都执行或者都不执行
如何保证原子性?
JMM只保证了基本读取和赋值的原子性操作,其他的不保证,如果想要使得某些代码片段具备原子性,
需要使用关键字synchronized,或者JUC中的lock。
总结:volatile关键字不具备保证原子性的语义
二、有序性
程序代码在执行过程中的先后顺序(编译器优化会导致不是开发者写的顺序)
具有保证顺序性的语义
Java提供三种方式保证有序性:
- 使用volatile保证有序性
- 使用synchronized保证有序性
- 使用显式锁Lock来保证有序性
volatile 变量规则
对一个变量的写操作要早于对这个变量之后的读操作。
根据字面的意思来理解是,如果一个变量使用volatile关键字修饰,
一个线程对它进行读操作,一个线程对它进行写操作,那么写入操作肯定要先行发生于读操作
三、可见性
当一个线程对共享变量进行修改,那么另外的线程可以立刻看到修改后的最新值。
Java提供三种方式保证可见性:
- 使用关键字volatile,当一个变量被volatile修饰,对于共享资源的读操作直接在主内存中进行,
当其他线程对该共享资源进行修改,会导致当前线程在工作内存中的共享资源失效,所以必须从主内
存中再次获取,对于共享资源的写操作当然是先要修改工作内存,然后刷新到主内存。 - synchronized能保证可见性
- 通过JUC的显式锁也能保证可见性。
总结:volatile具有保证可见性的语义
volatile关键字深入解析
语义
被volatile修饰的实例变量或者类变量具备如下两层语义
- 保证不同线程之间对共享变量操作时的可见性(一个线程修改,另外一个线程立刻看到最新值)
- 禁止对指令进行重排序操作。
volatile使用场景
- 多线程之间变量的可见性
- 有序性