Java内存模型——JMM总结

    技术2022-07-12  81

    JMM是什么?

    是一种规范,是关键字和工具类的原理,各JVM的实现都需要遵循它

    JVM内存结构 VS Java内存模型 VS Java对象模型【自己过】

    为什么需要JMM?

    ◇ 运算依赖处理器,不同处理器结果可能不一样 ◇ 无法保证并发安全 ◇ 需要一个标准,让多线程的结果可预期 ◇ C语言不存在内存模型概念

    JMM最重要的三点内容

    可见性

    {

    为什么会有可见性问题?

    CPU有多级缓存,导致读的数据过期 每个核心都会将需要的数据读到独立缓存中 数据修改后也是先写入到缓存中,再等待时机flush到主存中 导致有的核心读取到的是过期值

    JMM抽象了主内存和本地内存的概念,使我们不用在关心CPU一级缓存和二级缓存的问题,JMM定义了一套的读写内存数据的规范
    要注意的是,本地内存并不是真的给每块线程分配真的内存,而是JMM对寄存器、一级缓存、二级缓存进行了抽象。

    happens-before原则

    什么是happens-before?

    解决可见性问题的:在时间上,动作A发生在动作B之前,B保证能看见A,这就是happens-before。

    Happens-Before规则有哪些?
    主要考察

    锁操作(synchronized和Lock) volatile变量 一些工具类

    volatile关键字

    volatile是什么?

    volatile是一种同步机制,比synchronized或者Lock相关类更轻量,因为使用volatile并不会发生上下文切换等开销很大的行为。 如果一个变量别修饰成volatile,那么JVM就知道了这个变量可能会被并发修改。 但是开销小,相应的能力也小,虽然说volatile是用来同步的保证线程安全的,但是volatile做不到synchronized那样的原子保护,volatile仅在很有限的场景下才能发挥作用。

    volatile的适用场合

    作为触发器 Boolean Flag 【赋值】 如果一个共享变量自始至终只被各个线程赋值,而没有其他的操作,那么就可以用volatile来代替synchronized或者代替原子变量,因为赋值自身是有原子性的,而volatile又保证了可见性,所以就足以保证线程安全 用了volatile int x后,可以保证读取x后,之前的所有变量都可见。

    volatile的作用

    • 保证可见性 读一个 volatile 变量之前,需要先使相应的本地缓存失效,这样就必须到主内存读取最新值,写一个 volatile 属性会立即刷入到主内存。

    •禁止指令重排序

    volatile 小结
    volatile 修饰符适用于以下场景:某个属性被多个线程共享,其中有一个线程修改了此属性,其他线程可以立即得到修改后的值,比如boolean flag。volatile 属性的读写操作都是无锁的,它不能替代 synchronized,因为它没有提供原子性和互斥性。因为无锁,不需要花费时间在获取锁和释放锁上,所以说它是低成本的。volatile 只能作用于属性,我们用 volatile 修饰属性,这样 compilers 就不会对这个属性做指令重排序。volatile 提供了可见性,任何一个线程对其的修改将立马对其他线程可见。volatile 属性不会被线程缓存,始终从主存中读取。volatile 提供了 happens-before 保证,对 volatile 变量 v 的写入 happens-before 所有其他线程后续对 v 的读操作。volatile 可以使得 long 和 double 的赋值是原子的,后面马上会讲long 和 double的原子性。
    升华:对synchronized可见性的正确理解

    synchronized也可以达到同样的happens-before效果 这里关于synchronized有一个特别值得说的点,我们之前可能一致认为,使用了synchronized之后,synchronized会帮我们设立临界区,这样在一个线程操作数据的时候,另一个线程无法进来同时操作,所以保证了线程安全。其实这是不全面的,这种说法没有考虑到可见性问题。真正完整的说法是: synchronized不仅防止了一个线程在操作某对象时收到其他线程的干扰,同时还保证了修改好之后,可以立即被其他线程所看到。(因为如果其他线程看不到,那也会有线程安全问题)

    }

    重排序

    { 什么是重排序? 实际执行的顺序和代码在java文件中顺序的不一致

    重排序的好处? 提高处理速度

    重排序的三种情况 • 编译器优化 • 指令重排序 • 内存‘重排序’ [主要是指内存缓存的不一致]

    }

    原子性

    Processed: 0.012, SQL: 9