java内存模型剖析:
A:内存模型是什么鬼:
一、cpu和缓存一致性
计算机中cpu要和数据打交道,而数据往往是放到主存中去的,所以就可以理解成cpu和主存打交道。随着cpu的不断优化,任何存储器包括主存储器跟不上cpu的优化速度,甚至不在一个数量级上了,这个时候缓存出现了。
这样在cpu运行过程中,读数据的时候会将需要的数据从主存中复制一份到缓存中去,那么cpu就可以直接从它的缓存中读取和运算数据,运算完成之后,再将缓存中的数据刷新到主存中去。
随着cpu的能力再次不断的提升,一层缓存就又开始慢了起来,达不到要求,于是出现了多级的缓存,按照与cpu关系的紧密层度,分为一级缓存,二级缓存,三级缓存。
这样在cpu运行的过程中,读数据的时候会先从一级缓存中去读,如果没有找到再从二级缓存中去读,如果还没有就到三级缓存中去读。
随着cpu能力的再再次的不断升级,发展到了多核cpu,这样的话缓存的分配就出现了新的挑战,于是普遍认可每个cpu都可以含有自己的一级缓存,而二级缓存和三级缓存共享,或者是每个cpu可以容许含有自己的一级缓存和二级缓存,而三级缓存共享。
随着cpu能力的再再再升级,出现了多线程的功能。但首要解决的问题就是多线程冲突的问题——————-线程冲突怎么解决?
1.单核cpu:cpu核心的缓存只被一个线程访问,缓存独占,不会出现访问冲突的问题。
2.单核cpu,多线程:将成中的多个线程会同时访问缓存中的共享资源,cpu将某块儿内存加载到缓存中去的时候,不同线程访问的是相同的物理地址,相同的缓存位置,加上某个时刻只有一个线程在执行,所以不会出现缓存访问冲突。
3.多核cpu,多线程:每个cpu都容许有自己的一级缓存,多个线程访问进程中的某个共享资源的时候,每个cpu核心都会在各自的缓存中写自己的数据,cpu之间是互相不知道各自的情况的,所以这个时候就会发生缓存不一致的问题。
二、处理器优化
为了使得cpu内部的运算单元可以得到最大化的利用,处理器可能会对输入的代码进行乱序的处理。
三、指令重排序
为了对代码进行优化,jvm这种即时的编译器会对指令进行重排序。
B:并发编程中的问题
一、原子性
只在一个操作中,该操作不被中断,要么完成,要么不完成。cpu处理器优化就会导致原子性问题的发生。
二、即时可见性
指的是在多个线程操作一个共享变量的时候一个线程修改了这个变量的值,其他线程可以立即见到这个修改的值,缓存不一致性就会导致即时可见性问题的发生。
三、有序性
指的是程序按照代码的顺序来走。java的指令重拍序就会导致有序的性的发生。
C:什么是内存模型?
一、为了保证并发编程中的问题的出现,内存模型定了共享内存中的多线程程序读写操作的行为规范。
二、java中内存模型规定了所有的变量都存在主存中,每条线程容许有自己的工作内存,工作内存中存储了主存总的变量的副本拷贝,线程对变量的所有的操作,都只能在工作内存中进行。不同的线程见也无法直接访问对方工作内存中的变量,线程之间的变量访问均需要自己的工作内存和主存之间进行数据同步。JMM就是负责工作内存和主存中的数据同步。
D:java内存模型的实现
一、解决原子性:
synchronied关键字,保证了在同一时刻只容许一条线程操作。
二、解决可见性:
volatile关键字,保证了工作内存中被修饰的变量在被修改之后要立即同步到主内存中去,又由于其他线程读取变量的时候先从主内存中复制相关的数据到各自的工作内存中去,这样就可以被其他线程立即看到。
synchronized和final两个关键字也可以实现可见性,只不过实现的方式不同。
三、解决有序性:
通过synchronized和volatile来保证有序,两个实现的原理不同。volatile禁止java的指令重排序,而synchronized则是保证同一时刻只容许一条线程操作。