JMM:java内存模型
内存模型
-
java内存结构和java内存模型【Java Memory Model, JMM】不同;
-
jmm定义了一套在多线程读写共享数据【成员变量,数组等】时,对数据的可见性,有序性,原子性的规则和保障;
-
JMM:线程的内存【线程私有】和主内存【多线程共享】;
-
synchronized,同步关键字;
- 加synchronized关键字后,对应的monitor,监视器会对同步区起作用;
- monitor一共有三部分:Owner,EntryList,WaitSet;
-
原子性:
- 在多线程下,不会被其他线程干扰和中断,要么完整执行,要么不执行;
- 因为cpu的一个并发机制,会导致多线程的指令交错,所引起的问题;
-
可见性:
- 线程t在频繁访问主内存中的run值,JIT编译就会将run的值缓存到本地内存(如寄存器或线程栈),减少对主内存的访问;
- code cache代码缓存中的机器码一旦生成就不可修改,除非触发优化;
- 当main线程修改主内存中的run值时,但是t线程却永远看不到;
static boolean run = true; Thread t = new Thread(()->{ while(run) { } }, "t"); t.start(); thread.sleep(1000); run = false;- Volatile:易变关键字;
- 可以避免线程自己代码缓冲区查找变量的值,必须到主内存中获取它的值,必须直接操作主内存;
- 仅能保证可见性,不保证原子性,适合一个线程写,多个线程读;
- synchronized语句,既可以保证代码块的原子性,也可保证代码块的可见性,缺点:synchroized属于重量级操作,性能相对更低;
-
有序性:在同一个线程内,jvm会在不影响正确性的情况下,可能调正语句的执行顺序【指令重排】;
- 在一个线程下是不影响正确定结果的,但是多线程下,可能产生错误;
- eg:一个线程new 一个对象,但是当先赋值给变量在进行初始化时,另一个线程拿到的对象,可能还没进行初始化;
- 使用volatile关键字,解决指令重排问题,明确volatile修饰的相对位置;
-
happens-before:
- 规定了哪些写操作对其他线程的读操作可见;
- 它是可见性和有序性的规律总结;
- 线程对volatile变量的写,对接下来的其他线程对该变量的读可见;
- 线程解锁m之前对变量的写,对接下来的对m加锁的其他线程对该变量的读可见【前一个加锁解锁的写值,在相同锁的下的读可见性】;
- 线程start前对变量的写,在该线程开始后,对该变量的读是可见的【线程还没开始的写,对开始后的读可见】;
- 线程结束前对对边的写,其他线程在得知它结束后是可见的【isAlive(),join()】;
- 对线程打断前的写,对于其他线程得知被打断后,对该变量的读可见【主动打断别人,interrupted,然后可以读取它已经写入的值】;
- 对变量的默认值,【0,false,null】的写,对其他线程对该变量的读可见【第一次初始化】;
- 可见性,具有传递性;
- 这里的变量,成员变量或者静态变量;

浙公网安备 33010602011771号