是一种规范,是关键字和工具类的原理,各JVM的实现都需要遵循它
JVM内存结构 VS Java内存模型 VS Java对象模型【自己过】
◇ 运算依赖处理器,不同处理器结果可能不一样 ◇ 无法保证并发安全 ◇ 需要一个标准,让多线程的结果可预期 ◇ C语言不存在内存模型概念
{
CPU有多级缓存,导致读的数据过期 每个核心都会将需要的数据读到独立缓存中 数据修改后也是先写入到缓存中,再等待时机flush到主存中 导致有的核心读取到的是过期值
解决可见性问题的:在时间上,动作A发生在动作B之前,B保证能看见A,这就是happens-before。
锁操作(synchronized和Lock) volatile变量 一些工具类
volatile是一种同步机制,比synchronized或者Lock相关类更轻量,因为使用volatile并不会发生上下文切换等开销很大的行为。 如果一个变量别修饰成volatile,那么JVM就知道了这个变量可能会被并发修改。 但是开销小,相应的能力也小,虽然说volatile是用来同步的保证线程安全的,但是volatile做不到synchronized那样的原子保护,volatile仅在很有限的场景下才能发挥作用。
作为触发器 Boolean Flag 【赋值】 如果一个共享变量自始至终只被各个线程赋值,而没有其他的操作,那么就可以用volatile来代替synchronized或者代替原子变量,因为赋值自身是有原子性的,而volatile又保证了可见性,所以就足以保证线程安全 用了volatile int x后,可以保证读取x后,之前的所有变量都可见。
• 保证可见性 读一个 volatile 变量之前,需要先使相应的本地缓存失效,这样就必须到主内存读取最新值,写一个 volatile 属性会立即刷入到主内存。
•禁止指令重排序
synchronized也可以达到同样的happens-before效果 这里关于synchronized有一个特别值得说的点,我们之前可能一致认为,使用了synchronized之后,synchronized会帮我们设立临界区,这样在一个线程操作数据的时候,另一个线程无法进来同时操作,所以保证了线程安全。其实这是不全面的,这种说法没有考虑到可见性问题。真正完整的说法是: synchronized不仅防止了一个线程在操作某对象时收到其他线程的干扰,同时还保证了修改好之后,可以立即被其他线程所看到。(因为如果其他线程看不到,那也会有线程安全问题)
}
{ 什么是重排序? 实际执行的顺序和代码在java文件中顺序的不一致
重排序的好处? 提高处理速度
重排序的三种情况 • 编译器优化 • 指令重排序 • 内存‘重排序’ [主要是指内存缓存的不一致]
}