JMM

jit编译器优化 都是在多线程下
java - c -v 查看class文件指令

-xint 禁用编译器优化

1.永远的循环 可见性问题 编译器原因

2.加加减减 原子性问题
线程安全的问题 指令交错 轮流执行线程中的代码 使后期的结果覆盖了前期的结果

3.第四种可能 即使禁用编译器优化 也会出现问题
一个线程内指令顺序都修改 才可实现 几率很小
jcstress 压缩工具
actor注解 线程将会运行

编译器优化
流水线优化 同时执行多个指令
Cache优化

非流水线操作 - 流水线操作 增加寄存器 速度快 存在相互依赖的下面需要等待上面 此时下下面的继续执行

为了让 速度更快 产生了流水线优化 CPU层面

CPU有缓存 比内存速度更快 将数据从内存读取到缓存中 下次速度更快
这是就造成多核多缓存不一致问题 为保证一致性 建立一种协议 store buffer
这种优化

JMM内存模型 按照规则

JMM规范
1Race Condition
竞态条件 有读写操作共享变量

synchronize并不阻止线程切换 但是他切换后 发现锁被其他占着

两个共享变量 一个加一个不加 也会不安全

happens-Before

总结:

JMM是干啥的:Java内存模型 多线程下共享变量的执行顺序 可见性 有序性 原子性

多线程下的问题
1.永远的循环 此为可见性问题 循环达到阀值 java虚拟机jit编译器自动优化 直接替换工作内存值不再读取物理内存共享变量的值
再加一个线程 就能看到,没有循环够次数 继续走物理内存 ——Xint 关闭jit优化 工作内存+物理内存
2.加加减减 原子性问题 javap -c - v 查看字节码JVM指令 一个赋值操作有4个指令 两个线程之间指令交叉运行
cpu 线程间任务切换 一个线程一直占用CPU不可理
3.第四种可能 有可能指令重排 (并发压缩工具jcstress @Actor一个将被运行的方法 jar包运行)流水线优化
也有可能缓存优化

Processor优化 流水线优化:每个指令分 读取 执行 存储 三个阶段 执行完往寄存器存储结果
同一时刻 运行多个指令的不同部分 增加寄存器就行

流水线优化???指令切分 提高性能

有相互依赖的代码 流水线会停滞 不能同一时刻 运行不同部分 cpu继续走 走到没有依赖的代码 为了保障cpu的运行状态
指令继续向下走 此时就会产生指令的重排序 (有依赖关系的代码 才会有指令重排 目的 提高cpu效率)

多核 有缓存的问题 缓存优化:CPU有自己的缓存 两个cup读取了两个缓存 一个cpu改了 第二个cpu没有去内存读 导致缓存和内存值不同

解决:两个缓存之间通信 但这样通讯太慢 继续优化 存储缓冲区 优化写入效率 导致读取操作先执行

内存模型:介绍在什么情况会出现不安全的情况 按照规则 定义了一些规则 按照这些规则 线程就安全

1.竞态条件 为了更好地性能
2.同一线程内 保证执行顺序 例如 缓存 指令重排(流水线优化) volatile
3.synchronized 并不阻止线程切换 只是切换后拿不到锁

线程切换后按照什么规则??happens-Before

join等线程结束 在循环中加入 就可以解决可见性问题
action1先于action2

任务调度器
volatile 保证

第二节课:

内存屏障:对共享变量的操作

LoadLoad:防止之后的读取操作不能越过上面 但不能防止写

LoadStore:防止后面的写不能越过屏障

StoreStore:防止上面的写不能越过向下

上面三种是在同一线程内

Store+Load:防止 线程切换时

volitile原理:写入时加两个屏障 读时会加上两组屏障 loadload+loastore
不能保证原子性 需要配合 cas+volatile 乐观锁

cas原理:先比较旧值与共享变量是否一致 如果不一致就返回false

乐观锁:线程会阻塞,没有线程上下切换的成本

synchronized原理:操作系统提供的锁 monitor 阻塞的线程加入EntryList 悲观锁 同时也会内存屏障
分几个级别:锁升级自动实现
重量级:
轻量级:加锁解锁时间刚好错开
偏向锁:对比线程ID

不安全发布: new 对象时代码重排,构造方法造成指令重排
new时只分配空间 - 调用构造 - 赋值共享变量

解决办法:随便一个加final 最后一个赋值加valitile

双重检查锁:单例模式的 懒汉式模式并不是线程安全的 静态变量需要加volatile
原因:静态代码块中 new对象代码重排 造成得到没有构造完整的对象

/****屏障

java对象 - monitor地址

问题的解决

内存屏障:是一条指令 不同平台指令不同 所以也会造成不同型号机器 可能出现不同的效果

valitile 解决线程不可见问题 不能解决原子性问题

1:永远的循环 可见性 编译器优化 循环达到阀值 不再去内存去取 (工作内存???)
线程工作内存 距离CPU近 读取效率高 物理共享内存 慢几十上百倍 编译器优化 代码替换了

2:加加减减 原子性 表面上一行的代码 但其实运行时需要多个指令 不是原子操作 多线程之间指令交错运行
cpu线程轮流执行代码

3.第四种可能 流水线优化 有序性 有可能缓存优化

流水线优化 一条指令分多个阶段 读取 执行 存储 执行完一个阶段 向寄存器添加位置 cpu层面

相互依赖的 代码 流水线停滞 为了保证效率 保证流水线不停止 将下面没有依赖的代码 先执行

缓存优化:第四种可能也许为缓存 多核之间保证一致 使用cpu消息总线向对方发送消息 mesi协议

主存/内存:8g 16g  cpu缓存 1.2.3级缓存


storebuffer存储缓冲区 写的操作 需要多部执行 效率不高 此时就有了缓存优化  
 是一个异步的 接着走下面的方法

jmm内存规范:

竞态条件
线程内怎样保证有序
happendbefore 规则
1.starrt 规则
2.传递性规则
3.线程内规则
4.join规则
5.加锁解锁锁规则 第一个线程先加锁 第二个再解锁
6.volitile规则

同步动作:

volitile 修饰最后一个 最先读 最后写 加了四组屏障
只能保证有序性 可见性 不能防止线程间的指令交错 cas

使用valitile +cas 实现乐观锁

乐观锁 悲观锁对比

synchronized:monitor锁 锁+屏障 偏向锁 倾向所 重量锁

valitile 应用场景

安全发布 单例模式

1 回顾多线程 JMM 做思维导图JMM 多线程

看JMM第二篇 JVM

JMM概要

永远的循环 : jit 编译器优化 循环达到阀值 不再去主存读取 直接更改代码

加加减减 : 指令交叉 原子性问题 一组不是原子性的操作 发生了指令交叉

第四种可能:指令重排 有序性问题 缓存优化 流水线优化

流水线优化 : 指令的各个阶段,都是同时运作

缓存优化 : 从store buffer写入缓存为多部、异步

jmm规范:竞态条件

happendbefore规则 :

内存屏障:loadload loadstore storestore storeload

volitile : 加了两组屏障 保障了有序性
被修饰的变量更改后会强行刷入主存

synchronized: moniter 地址

不安全发布:new对象操作不是原子性 分配内存空间 初始化对象 将对象指向内存空间 指令重排导致对象未初始完成

单例模式 懒汉式 加volatile

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值