我们如果修改之前代码 , 就可以采用volatile修改:
package cn.itcast.jvm.t4.avo;public class Demo4_2 {static volatile boolean run = true;public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while(run){}});t.start();Thread.sleep(1000);run = false; // 线程t不会如预想的停下来}}
内存模型之有序性我们将在下面仔细介绍有序性的特点
有序性介绍首先我们简单介绍一下有序性的定义:
- 有序性就是指我们底层代码实现的具体顺序 , 在正常情况下是按正常顺序执行
- 同样底层也会进行部分优化 , 对于有序性的优化常常被称为指令重排 , 是指在不影响操作的前提下进行语句的优化调整
int num = 0;boolean ready = false;// 线程1 执行此方法public void actor1(I_Result r) {if(ready) {r.r1 = num + num;} else {r.r1 = 1;}} // 线程2 执行此方法public void actor2(I_Result r) {num = 2;ready = true;}
我们下面会给出其所有情况:// 具体分为四种情况 , 前三种属于正常的多线程无锁导致的情况 // 情况1:线程1 先执行 , 这时 ready = false , 所以进入 else 分支结果为 1// 情况2:线程2 先执行 num = 2 , 但没来得及执行 ready = true , 线程1 执行 , 还是进入 else 分支 , 结果为1// 情况3:线程2 执行到 ready = true , 线程1 执行 , 这回进入 if 分支 , 结果为 4(因为 num 已经执行过了)// 但是第四种!却是因为代码重排所导致的情况:
有序性分析首先我们在重新介绍一下指令重排:- JIT 编译器在运行时的一些优化 , 这个现象需要通过大量测试才能复现
线程2:ready = true;(由于操作更加简单 , 导致JIT将它放在前面编译)线程1:if判断 true线程1:r.r1 = num + num;(此时num为0) , 结果r1=0
JVM 会在不影响正确性的前提下 , 可以调整语句的执行顺序:// 下面是模拟情况:static int i;static int j;// 在某个线程内执行如下赋值操作// i为较为耗时的操作 , j为简单操作i = ...;j = ...;// 底层代码会认为i和j的赋值操作毫无关系 , 他们谁先执行都可以 , 所以会优先执行简单的操作// 所以我们的代码可能变为:static int i;static int j;j = ...;i = ...;
有序性实现我们的可见性经常通过一种修饰词来实现:- volatile 修饰的变量 , 可以禁用指令重排
int num = 0;boolean volatile ready = false;// 线程1 执行此方法public void actor1(I_Result r) {if(ready) {r.r1 = num + num;} else {r.r1 = 1;}} // 线程2 执行此方法public void actor2(I_Result r) {num = 2;ready = true;}
happens-before我们在最后插入一个简单的内容happens-before:- 规定了哪些写操作对其它线程的读操作可见 , 它是可见性与有序性的一套规则总结
- 线程 start 前对变量的写 , 对该线程开始后对该变量的读可见
static int x;x = 10;new Thread(()->{ System.out.println(x);},"t2").start();
- 线程对 volatile 变量的写 , 对接下来其它线程对该变量的读可见
volatile static int x;new Thread(()->{ x = 10;},"t1").start();new Thread(()->{ System.out.println(x);},"t2").start();
- 线程解锁 m 之前对变量的写 , 对于接下来对 m 加锁的其它线程对该变量的读可见
经验总结扩展阅读
- Linux学习环境搭建流程
- Archlinux + Dwm 配置流程
- 关于入门深度学习mnist数据集前向计算的记录
- 四十 Java开发学习----MyBatisPlus入门案例与简介
- jvm双亲委派机制详解
- FHE学习笔记 #2 多项式环
- django-environ学习
- 万字详解JVM,让你一文吃透
- 论文笔记 - GRAD-MATCH: A Gradient Matching Based Data Subset Selection For Efficient Learning
- MFC 学习笔记