并发编程的故事——共享模型之内存

共享模型之内存

文章目录

  • 共享模型之内存
  • 一、JVM内存抽象模型
  • 二、可见性
  • 三、指令重排序


一、JVM内存抽象模型

主要就是把cpu下面的缓存、内存、磁盘等抽象成主存和工作内存
体现在
可见性
原子性
有序性

二、可见性

出现的问题
t线程如果频繁读取一个静态变量,那么JIT编译器会把它存入到线程的缓存,那么就算主线程修改了主存中的静态变量也没有任何作用,因为t线程读取的是缓存里面的。所以程序判断仍然是错误无法停止。

@Slf4j(topic = "c.Test32")
public class Test32 {
    // 易变
    static boolean run = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(true){
                    if(!run) {
                        break;
                    }
            }
        });
        t.start();

        sleep(1);
            run = false; // 线程t不会如预想的停下来
    }
}

在这里插入图片描述
解决方案
volatile和synchronized可以让线程不能访问缓存,一定要访问主内存里面的run。

@Slf4j(topic = "c.Test32")
public class Test32 {
    // 易变
     static boolean run = true;
     static Object lock=new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(true){
                synchronized (lock){
                    if(!run) {
                        break;
                    }
                }

            }
        });
        t.start();

        sleep(1);
        synchronized (lock){
            run = false; 
        }

    }
}

加上sout也是可以解决可视化问题。原因是这个println是一个synchronize的方法,也就是要输出那么就会在同步块,同步块可以完成可视化,那么自然run就可以被读取。

public void println(boolean x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

三、指令重排序

为什么要指令重排?
因为各个语句都是由多个指令组成,相当于是多个分工,这些分工有的可以同时完成,那么就把他们先组合到一起。其它需要前一步的结果的指令就在后面排序等待。

诡异的结果
这里其实就是指令重排会导致这个结果是0。实际上就是线程2指令重排先执行了ready=true,然后被切换到线程1,刚好通过if先做出了计算,最后才是切换到线程2执行num=2
在这里插入图片描述
解决
使用volatile可以防止变量前面的代码重排序
在这里插入图片描述
volatile原理
volatile的原理其实就是内存屏障。写屏障就是把修改的变量之前的所有变量同步到主存中每次都是在主存中修改,而且防止前面的代码指令重排到屏障之后。如果是读屏障那么就是带有volatile变量以下的所有变量都同步到主存中,防止屏障以下的代码重排到屏障之前,也就保护了volatile属性。
保证了写屏障的变量是最新的
但是无法解决指令交错问题,也就是只能在本地线程保证指令有序,但是无法保证多线程的指令交错问题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
双重检查
单例模式为了防止多次加锁,可以先判空之后,再加锁,再判空。这样的好处就是创建对象之后,只需要判空,而不需要再次加锁。只有在第一次需要加锁创建对象,防止多个线程同时创建对象。
问题
第一个if代码会被指令重排,为什么会重排?
在这里插入图片描述
双重检查的问题根源分析(dcl)
关键就是if(INSTANCE==null)是一个在monitor之外的代码,那么产生的问题就是在执行INSTANCE=new Singleton()的时候,他并不是一个原子操作,包括了invokespecial执行构造方法指令和putstatic给引用赋值(找到对象的堆内存地址)
补充:那么这里synchronize为什么还是会出现指令重排?
原因是它本来就会产生指令重排,只不过在synchronize中不会产生原子化,可视化和有序化的问题,但这里是两个线程而且synchronize没有完全控制变量INSTANCE的原因。
在这里插入图片描述
在这里插入图片描述
解决方案
可以通过volatile的读写屏障防止代码指令重排到屏障之外,这样就能够避免invokespecial走到putstatic后。
在这里插入图片描述
在这里插入图片描述
happen-before(可见性)
synchronize
volatile
等待线程执行完之后再读取变量
静态变量写好之后,线程才调用
线程打断之前的修改
变量默认值
在这里插入图片描述
在这里插入图片描述
习题
balking习题
指令重排序问题,解决方案可以使用synchronize来把这些变量框住,防止其它线程切换的时候都通过了第一个if,导致重复执行问题
在这里插入图片描述
在这里插入图片描述
1、为什么加上final
原因就是防止类被继承,之后重写的方法带上单例对象被改变
2、怎么防止反序列化破坏单例
需要增加一个返回Obj的方法,直接返回单例对象,而不是通过字节码重新创建
3、为什么构造私有化
防止被创建很多次
4、初始化能保证线程安全吗
静态变量在类加载的时候完成了初始化
5、不把Instance变成public的原因
防止直接被修改,提供封装性,隐藏细节

在这里插入图片描述
1、字节码里面全部都是public final static的类对象,所以可以限制实例对象
2、不会有并发问题,在类加载的时候静态变量已经加载完了
3、不会被反射破坏单例,enum的设计
4、也不会被反序列化破坏,它实现了序列化和返回单例的方法
5、它是一个饿汉式
在这里插入图片描述
在这里插入图片描述
总结
可见性(jvm优化速度,把变量放进线程的缓存)
有序性(指令重排,优化执行速度)
happen-before写入是否对线程可见
volatile原理
同步模式balking


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/98601.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaWeb 速通Ajax

目录 一、Ajax快速入门 1.基本介绍 : 2.使用原理 : 二、Ajax经典入门案例 1.需求 : 2.前端页面实现 : 3. 处理HTTP请求的servlet实现 4.引入jar包及druid配置文件、工具类 : 5.Domain层实现 : 6.DAO层实现 : 7.Service层实现 : 8.运行测试 : 三、JQuery操作Ajax 1 …

vue使用qrcodejs2生成二维码

目录 概要 构建展示的vue组件qrcode.vue 组件的使用 概要 项目中用到需要展示二维码的样式&#xff0c;想到了qrcode 例如&#xff1a; 前提&#xff1a;安装包 npm install qrcodejs2 --save 构建展示的vue组件qrcode.vue <template><div style"width: …

Opencv基于文字检测去图片水印

做了一个简单的去水印功能&#xff0c;基于文字检测去图片水印。效果如下&#xff1a; 插件功能代码参考如下&#xff1a; using namespace cv::dnn; TextDetectionModel_DB *textDetector0; void getTextDetector() {if(textDetector)return;String modelPath "text_de…

拥抱储能新时代!科士达闪耀EESA第二届中国国际储能展览会

2023年8月30日&#xff0c;EESA第二届中国国际储能展览会在苏州国际博览中心拉开帷幕&#xff0c;科士达以“零碳光储数能未来”为主题&#xff0c;亮相G3-20展台&#xff0c;多维度展现户用光储、工商业储能、大型储能等解决方案&#xff0c;彰显安全、高效、可靠的产品性能和…

大数据时代下的精准营销

在大数据时代&#xff0c;人们的信息越来越透明&#xff0c;留在网络上的各种数据也是企业进行营销的一个重要的生产要素。一直以来&#xff0c;营销的科学性正是因为运用了自然科学中一级互联网中的数据收集手段&#xff0c;严谨的记录、搜集和分析消费者的各项数据和日常生活…

Java单元测试及常用语句 | 京东物流技术团队

1 前言 编写Java单元测试用例&#xff0c;即把一段复杂的代码拆解成一系列简单的单元测试用例&#xff0c;并且无需启动服务&#xff0c;在短时间内测试代码中的处理逻辑。写好Java单元测试用例&#xff0c;其实就是把“复杂问题简单化&#xff0c;建单问题深入化“。在编写的…

【核磁共振成像】相位差重建

目录 一、相位差map重建一般步骤和反正切函数主值范围二、反正切运算三、可预期相位误差和伴随场的校正四、图形变形校正 一、相位差map重建一般步骤和反正切函数主值范围 MRI是一个相敏成像模态&#xff0c;MR原始数据傅里叶变换后的复数图像中每个像素值有模和相位。标准模重…

Mysql高级语句

高级语句 1.按关键字排序 SELECT column1, column2, ... FROM table_name ORDER BY column1, column2, ... ASC|DESC ASC 是按照升序进行排序的&#xff0c;是默认的排序方式&#xff0c;即 ASC 可以省略。 SELECT 语句中如果没有指定具体的排序方式&#xff0c;则默认按 ASC…

【数据结构】——查找、散列表的相关习题

目录 一、选择填空判断题题型一&#xff08;顺序、二分查找的概念&#xff09;题型二&#xff08;分块查找的概念&#xff09;题型三&#xff08;关键字比较次数&#xff09; 二、应用题题型一&#xff08;二分查找判定树&#xff09; 一、选择填空判断题 题型一&#xff08;顺…

Leetcode328 奇偶链表

思路&#xff1a;分别处理奇偶&#xff0c;保存奇偶的第一个和最后一个节点&#xff0c;注意最后链接的时候需要把偶数的next去掉再拼接不然就成环了 class Solution:def oddEvenList(self, head: ListNode) -> ListNode:if not head or not head.next or not head.next.ne…

YOLOv5算法改进(10)— 替换主干网络之GhostNet

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。GhostNet是一种针对计算机视觉任务的深度神经网络架构&#xff0c;它于2020年由中国科学院大学的研究人员提出。GhostNet的设计目标是在保持高精度的同时&#xff0c;减少模型的计算和存储成本。GhostNet通过引入Ghost模块…

阿里云架构

负载均衡slb 分类以及应用场景 负载均衡slb clb 传统的负载均衡(原slb) 支持4层和7层(仅支持对uri(location),域名进行转发) 一般使用slb(clb) alb 应用负载均衡 只支持7层,整合了nginx负载均衡的各种功能,可以根据用户请求头,响应头 如果需要详细处理用户请求(浏…

【Dart】学习使用(二):基本类型

前言 基本类型是语言的基础。 Dart 语言支持以下基础类型&#xff1a;Numbers(int、double)&#xff0c; 整形Strings(String), 字符串Booleans(bool) , 布尔型Records((value1,value2)) 记录Lists(List ) 数组Sets(Set) 集合Maps(Map) 映射Runes(Runes,通常由 characters AP…

springBoot--终

目录 Web定制SpringMVC定制某些mvc配置定制mvc核心组件完全自定义mvc 静态资源静态资源映射静态资源缓存示例自定义静态资源规则配置方式代码方式 欢迎页Favicon&#xff08;网站图标&#xff09;路径匹配策略内容协商制定返回json类型数据制定返回xml类型数据制定返回自定义类…

2023年高教社杯 国赛数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模…

本地部署体验LISA模型(LISA≈图像分割基础模型SAM+多模态大语言模型LLaVA)

GitHub地址&#xff1a;https://github.com/dvlab-research/LISA 该项目论文paper reading&#xff1a;https://blog.csdn.net/Transfattyacids/article/details/132254770 在GitHub上下载源文件&#xff0c;进入下载的文件夹&#xff0c;打开该地址下的命令控制台&#xff0c;…

Vue安装过程的困惑解答——nodejs和vue关系、vue的项目结构

文章目录 一、为什么在使用vue前要下载nodejs&#xff1f;二、为什么安装nodejs后就能使用NPM包管理工具&#xff1f;三、为什么是V8引擎并且使用C实现&#xff1f;四、为什么会安装淘宝镜像&#xff1f;五、什么是webpack模板&#xff0c;为什么需要他&#xff1f;六、vue项目…

深入探索C语言自定义类型:打造你的编程世界

一、什么是自定义类型 C语言提供了丰富的内置类型&#xff0c;常见的有int, char, float, double, 以及各种指针。 除此之外&#xff0c;我们还能自己创建一些类型&#xff0c;这些类型称为自定义类型&#xff0c;如数组&#xff0c;结构体&#xff0c;枚举类型和联合体类型。 …

Unreal5(虚幻5)学习记录 快捷键

虚幻5学习记录 快捷键 世界场景中漫游&#xff08;镜头移动): 按住鼠标右键 键盘的W(前) S(后) A(左) D(右) E(上) Q(下)键 透视 透视 ALTG 上部分 ALTJ 底视图ALTSHIFTJ 左视图 ALTK 右视图 ALTSHIFTK 前视图 ALTH 后视图 ALTSHIFTH 内容浏览器 Ctrl Space 内容浏览器…

stm32CubeMX HAL W5500芯片介绍 第一章

W5500芯片介绍 文章目录 W5500芯片介绍简单简绍以太网以太网分五层&#xff1a;第一层物理层&#xff1a;第二层&#xff1a;数据链路层&#xff1a;第三层&#xff1a;网络层&#xff1a;第四层&#xff1a;传输层&#xff1a;第五层&#xff1a;应用层&#xff1a;以太网应用…