Java语言中内存模型 JMM 提供了一个统一的指导准则
Happen-before关系,是Java内存模型中多线程操作的可见性机制
具体表现,不止是synchronized volatile lcok操作顺序
线程的执行操作,保证了happen-before后面的操作,保证了基本的程序执行顺讯
对于volatile比那辆,写的操作,保证happen-before于该变量的读取操作
对于一个锁的解锁,保证happen-before 于加锁操作
对象构建完成,保证happen-before 于 finalizer的开始动作
线程内部的操作完成,保证happen-beofre其他线程的 Thread.join的线程
对于JMM,有一个建议,就是要克制技术的诱惑,除了编译器和JVM工程师,不然不要一口扎入胡不进去,增加无为的难度,也没有实践的价值
那么我们主要说的是
需要明白JMM要解决什么问题?
JMM如何解决可见性问题,类似volatile
Java早期尝试提供内存模型,这是为了避免C++因为没有内存模型,导致的处理器上不同的问题
而且,早期并不能保证一些多线程程序的正确性,比如双检锁,就是典型的并发编程中的安全发布失败,而且很难做到一次编译,处处运行
所以Java需要一个完善的JMM,能够让多方清晰地达成共识,简单的判断多线程程序什么样的执行顺序是正确的
对于JMM,分为JVM开发者和Java应用开发者
JVM开发者 编译器 更加关注于内存屏障之类的技术
Java应用开发者,关注于volatile synchronize之类的语义,类似happen-before的规则
JVM的内部运行数据区中运行如下,就是本地变量等数据从内存加载到缓存,寄存器,然后运行完成写入内存
上面的架构带来的一个问题,就是修改完成如果没有即时同步到缓存中,可能导致其他内核上线程还是旧的状态,原则上就是一致性的问题,多线程共享引入了复杂的数据依赖性,这就是JMM要解决的问题
JMM内部利用内存屏障,禁止某些重排序的方式,提供内存可见性保证,实现了各种happen-before规则,保证了不同编译器拥有一致的行为
比如一个volatile变量,JMM的操作如下
对于一个volatile变量
变量的写操作之后,编译器插入一个写屏障
变量的读操作之前,插入一个读屏障
内存屏障在变量的读写之后,会保证其他的线程修改对当前线程可见,即线程的会强制写入刷出处理器缓存,保证其他线程能够拿到最新的值
从应用开发者的角度,JMM提供的诸如volatile就是可以进行线程之间守护上下文的作用,线程A对volatile的赋值,会导致线程B在获取的时候可见性,当然也带来了一些线程的性能开销