如皋教育门户网站建设经验,wordpress列表无图像,广告设计与制作培训学校,网站效果图设计方案阿华代码#xff0c;不是逆风#xff0c;就是我疯#xff0c;你们的点赞收藏是我前进最大的动力#xff01;#xff01;希望本文内容能够帮助到你#xff01;
目录 一#xff1a;内存可见性问题
1#xff1a;代码解释
2#xff1a;结果分析
#xff08;1#xf…阿华代码不是逆风就是我疯你们的点赞收藏是我前进最大的动力希望本文内容能够帮助到你
目录 一内存可见性问题
1代码解释
2结果分析
1指令拆解
①load
②访问寄存器
2指令分析
3JVM代码优化
4解决问题
1引入.sleep()
2volatile
3准确描述 一内存可见性问题
内存可见性引起的多线程安全问题一个线程读一个线程写
package thread;import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-23* Time: 10:50*/
public class ThreadDemon26 {public static int flag 0;public static void main(String[] args) {Thread t1 new Thread(()-{while(flag 0){//等待t1线程输入flag的值只要不为0就能结束t1线程}System.out.println(t1线程结束);});Thread t2 new Thread(()-{System.out.println(请输入flag的值);Scanner scanner new Scanner(System.in);flag scanner.nextInt();});t1.start();t2.start();}
}1代码解释
这段代码想要表现出来的效果是t1t2线程同时运行通过t2线程中输入的flag的值来控制t1线程是否结束。
例如t2线程给flag赋值输入一个1那么此时t1线程就不会进入while循环打印t1线程结束。输入0那t1线程就陷入死循环 2结果分析
上文我们先后输入了1,0,2......都没能使t1线程结束这是为什么呢
1指令拆解
whileflag 0{}
这条语句其实有两个指令
①load
cpu从内存中读取flag的值load到cpu的寄存器上开销很大
②访问寄存器
cpu访问寄存器中存储的flag的值与0进行比较条件跳转指令开销低
此处不理解load和为什么开销很大请看阿华写的前面的文章哈有详细解释
2指令分析
重点条件①中load的操作读内存相较于②中访问寄存器的操作开销大的多。 上述while循环中①②这两条指令整体看执行的速度非常快等你scanner几秒钟了我while循环中①②可能都执行几亿次了cpu的计算能力非常强 此时JVM就会怀疑这个①号load 的操作是否还有存在的必要节省开销前几次可能还会load一下后面发现反正load 的值都一样速度太快了等不到我们scanner输入flag的值索性就把load这个操作给优化掉只留一个访问寄存器的操作指令访问之前寄存器中“缓存”的值大大提高循环的执行速度。 3JVM代码优化
在我们编译完代码后JVM会在保持你代码逻辑不变的前提下对你写过的代码进行智能分析并进行优化。
这个保持你代码逻辑不变的条件其实很苛刻单线程还好但是遇到多线程就难免会遇到一些bug。
我们上述的代码就是t2修改了内存但是t1并没有看到这就叫“内存可见性问题”
4解决问题
1引入.sleep()
治标不治本加入sleepload的循环次数减少JVM优化的迫切程度就会降低 2volatile
volatile关键字是强制性关闭优化保证每次循环都会从内存中读取数据。开销是变大了但是数据更准了
功能①保证内存可见性每次访问变量都要读取内存而不是优化到寄存器或者缓存器当中
功能②禁止指令重排序对于被volatile修饰的变量的操作指令是不能被重排序的 3JMM模型准确描述
我们的描述在上述代码中编译器发现每次循环都要读取读取内存开销太大于是就把读取内存操优化为读取寄存器操作。
JMM模型描述在上述代码中编译器发现每次循环都要读取“主内存”开销太大于是就把“主内存”中的数据拷贝到“工作内存”中后续每次读取都是到“工作内存”中。
注在JMM模型当中“主内存”对标内存“工作内存”对标寄存器缓存哪一套之所以这么叫是因为方便跨平台使用。