JMM是java内存模型,它描述的是和多线程相关的一组规范。通过这组规范定义了程序中对各个变量的访问方式。保证了不同jvm运行并发程序的结果的一致性和可靠性。
在JMM中有主存储器和工作存储器两种概念(主存和工作内存)。JMM规定所有变量都存储在主存中,并且每个线程都有自己的工作内存。线程的工作内存中保存主存中某些数据的拷贝,并且线程对变量的所有操作都必须在工作内存中进行,不能直接读写主存。不同线程也不能访问其他线程的工作内存,线程间通信必须通过主存完成。
JMM有三大特性:
原子性:一个或多个操作,要么全部执行,要么全部不执行。
可见性:只要有一个线程对共享变量(valoatile修饰才会成为共享变量)的值做了修改,其他线程都能马上收到通知,立刻获得最新值。
有序性:在线程内观察,操作都是有序的,而在线程内观察另一个线程,操作都是无序的(因为指令重排序和工作内存和主存的同步延迟)。
java提供了两个关键字volatile和synchronized来保证多线程间操作的有序性
synchronized通过加锁防止多个线程同时执行一段代码,线程执行互斥代码的过程如下:
- 获得同步锁;
- 清空工作内存;
- 从主内存拷贝对象副本到工作内存;
- 执行代码;
- 刷新主内存数据;
- 释放同步锁。
因此synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。
volatile有两个作用:禁止指令重排序,保证内存可见性。它是依靠内存屏障(内存栅栏)实现的,内存屏障提供三个功能:1、确保内存屏障前后的指令不会发生跨屏障的重排。2、对volatile修饰变量的修改会立刻刷入主存。3、对volatile变量的写操作会使其他CPU中的缓存失效,因此必须重新从主存读取。
但是volatile不能保证操作的原子性,因此不能保证多线程的并发有序。
参考: