侧边栏壁纸
博主头像
慢行的骑兵博主等级

贪多嚼不烂,欲速则不达

  • 累计撰写 29 篇文章
  • 累计创建 27 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

JMM内存模型与并发

慢行的骑兵
2021-10-14 / 0 评论 / 0 点赞 / 399 阅读 / 1,474 字
  • 并发的内容涉及的知识挺广的,需要并发还需要对Jvm有个很好的了解。在众多的知识中,我们要选取合适的知识学习,对于Android人员,学习并发的目的是为了让并发编程不会对于App造成卡顿。从以下四点来学习;
  • JMM并发内存模型(了解Java多线程下的处理流程)【了解线程并发的本质】;线程的安全性分析-锁;线程调度之线程池;J.U.C.核心之AQS(并发核心工具包应用,不同场景应用不同的工具);
  • 本篇笔记主要是记录第一点;

一.基础的认知

1.Cpu核数相关

  • 单核CPU一次只处理1线程;

  • 从我们的物理角度来讲,我们所有系统执行都是单线程串行;

  • 多核之间存在并行;

  • 微观上来讲是串行,宏观上来讲是并行、并发;

  • 1核CPU处理资源是有时间片的划分。我们自己在对于程序处理的感知

2.高速缓冲区

  • 内存条的效率跟不上CPU的处理效率(略写);

二.JMM内存模型

1.JMM内存模型

  • JAVA多线程内存模型跟CPU内存模型类似,是基于CPU缓存模型来建立的,java线程内存模型是标准化的,屏蔽了底层计算机的不同;

01.Jmm内存模型

  • JMM与JVM
    • JMM是java实际上的内存架构;
    • JVM运行时数据区,指的是代码所产生的数据的管理区域;
  • 线程不安全的根源:是因为引入了工作内存。

2.JMM原子操作示例

  • 代码
public class JMMTest {
    public static boolean initFlag = false;
    public static void main(String[] args) {
        //线程1
        new Thread(()->{
            System.out.println("begin...........");
            while(!initFlag){
            }
            System.out.println("ending.............");
        }).start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
		
        //线程2
        new Thread(()->{
            prepare();
        }).start();
    }
    public static void prepare(){
        System.out.println("prepare assgin  begin.......");
        initFlag = true;
        System.out.println("prepare assgin  end.......");
    }
}
  • 运行结果
begin...........
prepare assgin  begin.......
prepare assgin  end.......
  • 结合上面1的图可以知道工作内存的存在;

3.控制总线

  • 比较复杂,我们先简单理解:消息队列;

4.JMM内存模型8大原子操作

  • read(读取):从主内存中读取数据
  • load(载入):将主内存读取到的数据写入工作内存
  • use(使用):从工作内存读取数据来计算
  • assign(赋值):将计算好的值重新赋值到工作内存当中
  • store(存储):将工作内存数据写入主内存
  • write(写入):将存入的数据变量值赋值给主内存中的共享变量
  • lock(锁定):将主内存变量加锁
  • unlock(解锁):将主内存变量解锁
  • 了解了控制总线和JMM内存模型8大原子操作之后,我们根据代码来分析具体的JMM内存模型8大原子操作

02.按照代码执行流程来分析JMM原子操作

  • 最终主内存的initFlag变成了true;但是线程的工作内存的initFlag仍然为false;

  • sleep会释放工作内存的内容;

  • 2中的代码可以通过增加volatile来处理;

5.JMM内存模型8大原子操作图示

03.JMM内存模型8大原子操作图示

三.volatile

  • volatile关键字是用来处理线程并发的可见性问题
    • 总线嗅探机制
    • 原子操作过程
    • 会使我们其它CPU工作内存的共享变量失效
    • 在底层的实现过程中,volatile对象,不单单是用来处理可见性问题,它也用来被处理顺序问题;
补充:
	虚拟机最轻量的同步机制
	
	修饰变量:保证了数据的可见性(告诉虚拟机:这个变量很容易发生变化,再去用它的时候,经常的从主内存中去读取),但不能保证操作的原子性。	

1.Volatile缓存可见性实现原理

  • 底层实现主要通过一条汇编指令lock前缀指令,它会锁定这块内存区域的缓存(缓存行锁定)并写回到主内存中
  • Inter架构软件开发者手册中对lock指令的解释:
    • 会将当前处理器缓存行的数据立即写回到系统内存
    • 这个写回内存操作会引起其他CPU缓存了该地址的数据无效(MESI)
    • 提供内存屏障功能,是lock指令不会进行重排

四.JAVA底层对应转换汇编语言查看

五.指令重排序

  • 定义:在计算机执行指令的顺序在经过程序编译器编译之后形成的指令序列;

  • 一般而言,这个指令序列是会输出确定的结果;以确保每一次的执行都有确定的结果。但是,一般情况下,CPU和编译器为了提升程序执行的效率,会按照一定的规则允许进行指令优化。在某些情况下,这种优化会带来一些执行的逻辑问题,主要的原因是代码逻辑之间是存在一定的先后顺序。在并发执行情况下,会发生二义性,即按照不同的执行逻辑,会得到不同的结果信息。

六.内存屏障

  • 实际上就是如果CPU在指令优化是给与一个标记位置,碰到此位置不进行优化;

七.总结

  • 重点是volatile关键字,处理了两个问题
    • 1.可见性问题
      • JMM内存模型,工作内存
    • 2.指令顺序问题
      • 指令重排的概念
0

评论区