1.什么是JMM?
JMM 是Java内存模型( Java Memory Model),简称JMM
2.JMM的三大特性:
JMM的三大特性:原子性、可见性、有序性。
1.原子性
一个或多个操作,要么全部执行,要么全部不执行(执行的过程中是不会被任何因素打断的)。
2.可见性
只要有一个线程对共享变量的值做了修改,其他线程都将马上收到通知,立即获得最新值。
3.有序性
有序性可以总结为:在本线程内观察,所有的操作都是有序的;而在一个线程内观察另一个线程,所有操作都是无序的
指令重排:我们正常写的代码是按照从上往下的顺序执行的,但是编译器可能为了优化代码会对我们写的代码重新排序,这种操作单线程下基本没问题,但是多线程下就可能会出现有序性问题
有序性问题 指的是在多线程的环境下,由于执行语句重排序后,重排序的这一部分没有一起执行完,就切换到了其它线程,导致计算结果与预期不符的问题。这就是编译器的编译优化给并发编程带来的程序有序性问题。
二.volatile
被volatile修饰的变量有两个特点:有序性,可见性
内存屏障,通过volatile来实现,就是说,当volatile修饰一个变量时,这个变量的上下就带上了内存屏障
volatile特性
1.可见性
-
①. 保证不同线程对这个变量进行操作时的可见性,即变量一旦改变所有线程立即可以看到
-
②. 代码展示
不加volatile,没有可见性,程序无法停止
加了volatile,保证可见性,程序可以停止package now; import java.sql.Time; import java.util.concurrent.TimeUnit; class Student{ int age = 0; //volatitle int age = 0; public void changeage(){ this.age = 50; } } /** * 验证volatile的可见性 * 假如 int age = 0; age变量前面没有用volatile 关键字 修饰 * volatile可以保证可见性,及时通知其他线程,主物理内存的值已经被修改 */ public class VolatileTest { public static void main(String[] args) { //main是一切方法的运行入口 Student student = new Student(); //学生类 // AAA 第一个线程 new Thread(() -> { System.out.println(Thread.currentThread().getName() + "\t come in"); //暂停一会线程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } student.changeage(); System.out.println(Thread.currentThread().getName() + "\t change age to " + student.age); }, "AAA").start(); // main 第二个线程 while(student.age == 0){ //main线程 循环等待student.age的变化 知道age不等于0 } System.out.println(Thread.currentThread().getName() + "\t mission over" + student.age); } }
2.无原子性
volatile只能保证拿到的数据是最新的,假如在上图的数据加载和数据赋值之间时值改变了,那么这个线程就会作废,导致缺少线程,所以无法实现原子性,下图输出小于1000
3.有序性
在哪些地方可以使用volatile?
●① 单一赋值可以,but含复合运算赋值不可以(i++之类)
1.volatile int a = 10
2.volatile boolean flag = false
●②. 状态标志,判断业务是否结束