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

news2024/10/7 14:26:38

共享模型之内存

文章目录

  • 共享模型之内存
  • 一、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


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android安卓实战项目(12)—关于身体分析,BMI计算,喝水提醒,食物卡路里计算APP【支持中英文切换】生活助手类APP(源码在文末)

Android安卓实战项目(12)—关于身体分析,BMI计算,喝水提醒,食物卡路里计算APP【支持中英文切换】生活助手类APP(源码在文末🐕🐕🐕) 一.项目运行介绍 B站演示…

第8章 字符输入/输出和输入验证

本章介绍以下内容: 更详细地介绍输入、输出以及缓冲输入和无缓冲输入的区别 如何通过键盘模拟文件结尾条件 如何使用重定向把程序和文件相连接 创建更友好的用户界面 在涉及计算机的话题时,我们经常会提到输入(input)和输出&#…

Facebook登录SDK

一、Facebook SDK接入 官方文档:https://developers.facebook.com/docs/facebook-login/android 按照流程填写完成 1、选择新建应用 如果已经创建了应用就点【搜索你的应用】,忽略2、3步骤 2、选择【允许用户用自己的Facebook账户登录】 3、填写应用…

简析vue文件编译——AST

简介 首先了解一个概念AST(abstract syntax tree)抽象语法树,按照大多数教程中的描述,这是一种源代码的抽象语法结构树,树上的每个节点都表示源代码中的一种结构,将源码中的各种嵌套括号等形式&#xff0c…

Android安卓实战项目(13)---记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末)

Android安卓实战项目(13)—记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末🐕🐕🐕) 一.项目运行介绍 B站…

antd实现年日输入框联动

效果: 1、默认显示年,日期区间默认显示今年2023——2024 年份显示前5年后5年 2、如果选择了月份,日期区间显示从1月份到12月份 部分代码: (react 使用class类组件)

Lee滤波python实现(还包括frost等滤波)

Lee滤波按定义实现: from scipy.ndimage.filters import uniform_filter from scipy.ndimage.measurements import variancedef lee_filter(img, size):img_mean uniform_filter(img, (size, size))img_sqr_mean uniform_filter(img**2, (size, size))img_varian…

最小生成树 -prim算法

一般无向图建图稠密图-prim算法稀疏图-kruskal算法 prim : 加点法 1.先随机选一个点,加入集合 ,之后寻找最短的距离的点加入集合,行程最小生成树。 2.注意最小生成树是不能有回路的, 所以可以把回路设置成最大值,即假装…

idea使用maven时的java.lang.IllegalArgumentException: Malformed \uxxxx encoding问题解决

idea使用maven时的java.lang.IllegalArgumentException: Malformed \uxxxx encoding问题解决 欢迎使用Markdown编辑器1、使用maven clean install -X会提示报错日志2、在Poperties.java文件的这一行打上断点3、maven debug进行调试4、运行到断点位置后,查看报错char…

贝锐蒲公英异地组网方案,如何阻断网络安全威胁?

随着混合云和移动办公的普及,企业网络面临着越来越复杂的安全威胁环境。 大型企业有足够的能力和预算,构建覆盖全部个性化需求的定制化网络安全方案。 但对于广大中小企业来说,由于实际业务发展情况,他们难以在部署周期、预算成本…

Redis数据结构应用场景及原理分析

目录 一、Redis介绍 二、应用场景 2.1 String应用场景 2.2 Hash应用场景 2.3 List应用场景 2.4 Set应用场景 2.5 Zset应用场景 一、Redis介绍 单线程多路复用底层数据结构:全局哈希表(key-value) 二、应用场景 2.1 String应用…

安装centos7修改网关时出现ifconfig命令找不到的解决方法

系列文章专栏 学习以来遇到的bug/问题专栏 文章目录 系列文章专栏 一 问题描述 二 解决方法 2.1 原因分析 前言 本文主要介绍安装centos7修改网关时出现ifconfig命令找不到的解决方法 一 问题描述 安装centos7修改网关时出现ifconfig命令找不到的情况 二 解决方法 2…

Revit SDK:SolidSolidCut 实体几何裁剪

前言 这个例子介绍了 Revit 中的一个实体几何裁剪。 内容 这个例子介绍如何使用 SolidSolidCutUtils 的接口来做几何裁剪以及取消几何裁剪。内容相对来说非常简单。 namespace Autodesk.Revit.DB {public static class SolidSolidCutUtils{public static void AddCutBetwee…

vue3组合式api bus总线式通信

vue2中可以创建一个 vue 实例, 做为 总结来完成组件间的通信 但是在vue3中, 这种方法是不能使用的。 因为vue3中main.js中, 使用的createApp() 没有机会再写 new Vue了 但是我们可以使用 mitt 的插件来解决这个问题 vue3 bus组件的用法 安装…

Mysql表关联简单介绍(inner join、left join、right join、full join不支持、笛卡尔积)

文章目录 0. 交集、并集、差集含义说明1. 简单演示上图七种情况0. A、B表数据准备1. left outer join 简称 left join 左表所有数据,右表关联数据,没有的以null填充2. right outer join 简称 right join,右表所有数据,左表关联数据…

【SpringCloud】SpringCloud整合openFeign

文章目录 前言1. 问题分析2. 了解Feign3. 项目整合Feign3.1 引入依赖3.2 添加注解3.3 编写Feign客户端3.4 测试3.5 总结 4. 自定义配置4.1 配置文件方式4.2 Java代码方式 5. Feign使用优化5.1 引入依赖5.2 配置连接池 6. Feign最佳实践6.1 继承方式6.2 抽取方式 前言 微服务远…

报错处理:Too many open files

报错处理 Too many open files 报错环境 Linux 排错思路 当打开的文件句柄超过系统允许的最大值时,会出现该错误。这可能是由于系统参数限制或者应用程序打开了过多的文件导致的。 解决方法 可以通过修改系统参数来增加最大允许打开文件句柄数。 临时性修改&#xf…

ssm农业视频实时发布管理系统源码

ssm农业视频实时发布管理系统源码108 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm package com.controller;import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; impo…

ui网页设计实训心得

ui网页设计实训心得篇一 通过这次实训对这门课程的学习,做好网页,并不是一件容易的事,它包括网页的选题、 内容采集整理、 图片的处理、 页面的排版设置、 背景及其整套网页的色调等很多东西。 所以我得出一下总结: 一、 准备资…

将本地jar打包到本地maven仓库或maven私服仓库中

将本地jar包打包到本地的maven仓库中的命令&#xff1a; mvn install:install-file -DgroupIdtebie.applib.api -DartifactIdapiclient -Dversion1.0-SNAPSHOT -Dfile本地jar路径 -Dpackagingjar说明&#xff1a; DgroupId pom中的<groupId></groupId> Dartifact…