java内存模型(JMM)是一种规范,定义了程序中变量的访问规则,目的是解决因为多线程经过共享内存进行通讯时,由工做内存数据不一致、编译器指令重排序、处理器优化等带来的原子性、有序性和缓存一致性等问题。
在多核CPU的环境下,多线程分别在不一样的核心上执行,当多个线程访问进程中的某个共享内存时,每一个核心都会在各自的CPU缓存中保留一份共享内存的拷贝,因为多核是能够并行的,可能会出现多个线程同时写各自的缓存的状况,而各自cache之间的数据就有可能不一样。
Java内存模型分为主内存和工做内存,同时模型规定了全部的变量(共享变量)都存储在主内存中,每条线程有本身的工做内存,线程的工做内存中保存的变量是主内存中的变量的一个副本,线程对变量的全部操做都必须在本身的工做内存中进行,不能直接读写主内存。不一样的线程之间也没法直接访问对方工做内存中的变量,线程间变量的传递均须要本身的工做内存和主存之间进行数据同步进行。
java内存模型要解决的就是工做内存与主内存之间的数据同步问题。java中的volatile、synchronized、final以及concurren包等就是解决这个问题的,
java中的synchronized关键字经过monitorenter和monitorexit两个字节码指令实现加锁解锁操做,保证同一时刻只有一个线程能获取锁而后执行同步代码,而且在释放锁以前会将对变量的修改刷新到主存中,从而保证原子性、可见性和有序性。
volatile关键字能够保证变量的可见性 和 禁止指令重排序优化。被volatile修饰的变量在被修改后会当即同步到主内存,并将其余线程中的这个变量副本置失效,其余线程在访问这个变量以前都从主内存中刷新。同时,对应volatile变量,Java内存模型会在写操做后插入一个写屏障指令,在读操做前插入一个读屏障指令,内存屏障可以阻止屏障两侧的指令重排序,从而保证了程序的有序性,另外内存屏障还会强制更新一次不一样CPU的缓存。java
ps:volatile关键字仅能实现对原始变量(如boolen、 short 、int 、long等)操做的原子性,但须要特别注意, volatile不能保证复合操做的原子性,即便只是i++,实际上也是由多个原子操做组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操做的i是同一块内存,但依然可能出现写入脏数据的状况。
对于64位的long和double,若是没有被volatile修饰,那么对其操做能够不是原子的。在操做的时候,能够分红两步,每次对32位操做。
若是使用volatile修饰long和double,那么其读写都是原子操做
对于64位的引用地址的读写,都是原子操做缓存
1.volatile仅能使用在变量级别; synchronized则可使用在变量、方法、和类级别的2.volatile仅能实现变量的修改可见性,并不能保证原子性;synchronized则能够保证变量的修改可见性和原子性3.volatile不会形成线程的阻塞; synchronized可能会形成线程的阻塞。4.volatile标记的变量不会被编译器优化;synchronized标记的变量能够被编译器优化。多线程
1)对变量的写操做不依赖于当前值
2)该变量没有包含在具备其余变量的不变式中jvm