共享模型之内存

JMM

JMM:Java内存模型。定义了主存(所有线程共享的数据)、工作内存(每个线程对应的私有数据)的抽象概念。

JMM存在以下几个特征

  • 原子性:保证指令不会受到线程上下文切换所影响。
  • 可见性:保证指令不会被CPU缓存所影响。
  • 有序性:保证指令不会被CPU指令并行优化的影响。

可见性

public class test{
    static boolean run = true;
    public static void main(String[] args){
        new Thread(()->{
            while(run){
                //……
            }
        }).start();

        System.out.println("主线程结束子线程");
        run = false;
    }
}

主线程结束子线程

理论上来讲,当run改为false后,子线程也会跟着结束并结束程序运行。但是实际并不会结束程序,因此主线程结束并不会让子线程结束while循环。

这就是可见性一个体现,不受CPU缓存影响。从JMM解释来看。

解决方案

将run变量使用volatile(异变)关键词修饰。这样就不会从缓存区获取run值,而是从主存中获取。

volatile关键词用来修饰成员变量与静态成员变量,修饰局部变量没意义,因为局部变量是线程私有的,主存中都没带存的。

或是使用synchroized加锁后来修改run的值。因为synchroized在进入保护的代码前会废弃工作内存重新再去主存中读取。[拓展:synchronized在获取锁之前需要去主存中获取保护代码块所需要的变量存储在工作内存中,当释放锁时会将工作内存中的变量刷新到主存中]。

volatile只能解决可见性问题,并不能解决指令交错的问题,因此只适用于一个线程写多个线程读的场景,比如说两个线程分别进行i++与i--,并不能保证能够正常得出结果。

synchronized虽然可以解决原子性与可见性的问题但是属于重量级操作,性能比较低。

有序性

JVM在不影响程序运行的正确性的前提下,会进行指令重排。在多线程下可能会存在安全隐患。

一般情况下赋值操作,是不在乎谁先谁后,因此可以进行指令重排的。但是在多线程下,有时需要使用这些变量,那么可能会存在安全隐患。

public class demo6 {
    static int num;
    static boolean ready;
    static int result;

    public static void main(String[] args) {
        //线程1
        new Thread(() -> {
            if (ready) {
                result = num + num;
            } else {
                result = 1;
            }
        }).start();

        new Thread(() -> {
            num = 2;
            ready = true;
        }).start();
    }
}

对以上代码进行分析,原则上num与ready的赋值操作先后顺序是无所谓的。但是此时还存在线程1使用这两个变量,这两个变量的结果会对result的结果产生影响。

  • 结果1:result值为1,此结果是因为先对num赋值又或是没有赋值,此时ready为false,走了线程1中的else代码。
  • 结果2:result值为4,此结果是因为线程2对两个值进行了赋值后,线程1才进行执行走的是if中的代码。
  • 结果3:result值为0,此结果是对ready赋值后,但是num还没有进行赋值去执行线程1中的if中代码,导致result值为0。

以上是指令重排序带来的危害,无法预测程序的运行结果,禁止指令重排只需要对ready变量使用volatile修饰即可。

如何保证可见性

写屏障:在volatile修饰的变量之前包括volatile变量,对于共享变量的变动会同步到主存。

读屏障:对于volatile变量之后的变量读取需要从主存中读取。

如何保证有序性

写屏障:在指令重排序时,不会将写屏障之前的代码排序到写屏障之后。

读屏障:在指令重排序时,不会将读屏障之后的代码排序到读屏障之前。

写屏障只能保证能够读取到最新的数据,并不能解决指令交错的问题。有序性只能保重本线程中的代码不会被指令排序

关于单例模式中双重检查锁出现的问题

通过查看创建对象部分的字节码文件来看

前两行是获取单例对象并进行非空判断的字节码,如果不为空则跳转37处。这是第一层if判断

从6到36部分,是synchronized部分字节码,意思是获取类对象,复制一份存储在字符常量池中加锁,获取单例对象判断是否为空,为空则创建出一个对象,复制一份地址,根据地址调用构造器(21)后对单例对象进行复制后解锁,如果不为空跳转到37处。

问题在于21与24可能通过指令重排序后互换位置。那么在多线程中可能出现以下问题

线程2拿到了没有初始化的值去使用,造成空指针异常。

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

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

相关文章

【数据集】全网最全的常见已公开医学影像数据集

目录 一,极市医学数据集汇总 1.CT 医学图像 ​编辑 2.恶性与良性皮肤癌 3.白内障数据集 4.胸部 X 光图像(肺炎) 5.用于图像增强的内窥镜真实合成曝光过度和曝光不足帧 6.医学家 7.乳房组织病理学图像 8.皮肤癌 MNIST:HA…

elementPlus之home页面布局

可以根据自己喜欢的格式选择 现在 header 部分 Aside 部分 Main部分 加上背景色以及命名 <template><div class="common-layout"><el-container><el-header class="homeHeader"><div class="headerTitle">Dev…

【Flutter】设置顶部状态栏的显示、隐藏、半透明灰色显示

【Flutter】设置顶部状态栏的显示、隐藏、半透明灰色显示 设置方法&#xff1a; // 这种模式不现实状态栏 SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); // 这种模式显示状态栏 SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); // 修…

Yakit工具篇:WebFuzzer模块之热加载技术

简介 官方定义&#xff1a; 什么是热加载&#xff1f; 广义上来说&#xff0c;热加载是一种允许在不停止或重启应用程序的情况下&#xff0c;动态加载或更新特定组件或模块的功能。这种技术常用于开发过程中&#xff0c;提高开发效率和用户体验。 在Yakit 的Web Fuzzer中&…

C#调用ffmpeg从视频提取图片

微信公众号“CSharp编程大全”的文章《C#从视频提取图片&#xff1f;》介绍了基于Microsoft.DirectX.AudioVideoPlayback.Video类实现从视频提取图片的方式&#xff0c;本来是想学习并测试该类的用法&#xff0c;但实际测试过程中却没有测通。百度从视频提取图片&#xff0c;网…

Kotlin学习——kt里面的函数,高阶函数 函数式编程 扩展函数和属性

Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复用代码&#xff0c;以实现高效编程。 https://play.kotlinlang.org/byExample/01_introduction/02_Functio…

如何使用Python在3dMax控制网格对象?

我们以一个在3dMax中使用Python脚本在网格对象对象上创建水波变形作为例子。 首先&#xff0c;在3dmax创建两个对象&#xff0c;一个“box”对象&#xff0c;将长宽方向的分段设置的多一些&#xff08;目的是为了后面的水波变形&#xff09;&#xff0c;一个“点”帮助对象&am…

P13 C++ 类 | 结构体内部的静态static

目录 01 前言 02 类内部创建静态变量的例子 03 在类的内部创建静态变量的作用 04 最后的话 01 前言 本期我们讨论 static 在一个类或一个结构体中的具体情况。 在几乎所有面向对象的语言中&#xff0c;静态在一个类中意味着特定的东西。这意味着在类的所有实例中&#xff…

AI换脸教程

方法一、MJ换脸大法 1.点击这个网站添加一个机器人到自己的服务器 https://discord.com/oauth2/authorize?client_id1090660574196674713&permissions274877945856&scopebot 2. /saveid 回车选择你自己的照片&#xff0c;并且在名字框命名身份&#xff0c;回车 3.…

Linux关于定时任务crontab相关知识了解配合理解shell反弹远程控制

Linux关于定时任务crontab相关知识了解配合理解shell反弹远程控制 几点需要知道的信息 【1】crontab一般来说服务器都是有的&#xff0c;依赖crond服务&#xff0c;这个服务也是必须安装的服务&#xff0c;并且也是开机自启动的服务&#xff0c;也就是说&#xff0c;他基本上是…

LiveGBS流媒体平台GB/T28181功能-查看国标设备会话列表直播会话、回放会话、下载会话、对讲会话

LiveGBS流媒体平台GB/T28181功能-查看国标设备会话列表直播会话、回放会话、下载会话、对讲会话 1、会话列表2、会话类型3、搭建GB28181视频直播平台 1、会话列表 LiveGBS-> 国标设备-》点击在线状态 点击会话列表 2、会话类型 下拉会话类型可以看到 直播会话、回放会话、…

Rust UI开发(一):使用iced构建UI时,如何在界面显示中文字符

注&#xff1a;此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库&#xff0c;用于为rust语言程序构建UI界面。 iced的基本逻辑是&#xff1a; UI交互产生消息message&#xff0c;message传递给后台的update&#xff0c;在这个函数中编写逻辑&#xff0c;然后通过…

python安装redis库

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

#BUG SHOW# 深挖一个6年前的老“bug”

引言 最近参与了一个业务迁移的项目&#xff0c;需要把站点A迁移到站点B。不同的站点拥有各自独立的服务和数据库&#xff0c;可以说是毫无关联。为了兼容迁移过程中的存在的一部分特殊交易数据&#xff08;正向[支付]交易在站点A&#xff0c;但逆向[退款]操作在站点B操作&…

使用new Vue()的时候发生了什么?

前言 Vue.js是一个流行的JavaScript前端框架&#xff0c;用于构建单页面应用&#xff08;SPA&#xff09;和用户界面。当我们使用new Vue()来创建一个Vue实例时&#xff0c;Vue会执行一系列的初始化过程&#xff0c;将数据变成响应式&#xff0c;编译模板&#xff0c;挂载实例…

基于WSL2+Docker+VScode搭建机器学习(深度学习)开发环境

基于WSL2DockerVScode搭建机器学习(深度学习)开发环境 内容概述&#xff1a;由于最近配发了新的工作电脑但不想装双系统&#xff0c;因此通过本博文来记录基于Windows子系统WSLDocker搭建机器学习与深度学习开发环境的流程步骤&#xff0c;同时记录该过程中所遇到的相关问题及解…

FFmpeg命令分隔视频

有一个视频如a.mp4&#xff0c;此视频采用帧率为30生成&#xff0c;共有299帧&#xff0c;这里通过FFmpeg命令分隔成1秒一个个的小视频&#xff0c;即每个小视频帧数为30帧。 用到的FFmpeg参数如下所示&#xff1a; (1).-i:指定输入视频文件的名称&#xff1b; (2).-c:指…

Guitar Pro软件8.0官方最新版本下载

Guitar Pro 8是一款由法国Arobas Music公司开发的吉他学习与MIDI音序制作辅助软件&#xff0c;它具有丰富的功能&#xff0c;包括吉他谱、六线谱、四线谱绘制、打印、查看、试听等方面&#xff0c;能够帮助音乐爱好者更方便地进行音乐学习和创作。Guitar Pro 8拥有独特的gtp格式…

Jmeter对图片验证码的处理

​对图片验证码的处理 在web端的登录接口经常会有图片验证码的输入&#xff0c;而且每次登录时图片验证码都是随机的&#xff1b;当通过jmeter做接口登录的时候要对图片验证码进行识别出图片中的字段&#xff0c;然后再登录接口中使用&#xff1b; 通过jmeter对图片验证码的识…

【手写实现一个简单版的Dubbo,深刻理解RPC框架的底层实现原理】

手写实现一个简单版的Dubbo&#xff0c;深刻理解RPC框架的底层实现原理 RPC框架简介了解Dubbo的实现原理服务暴露服务引入服务调用 手写实现一个简单版的Dubbo服务暴露ServiceBeanProxyFactory#getInvokerProtocol#exportRegistryProtocol#export 服务引入RegistryProto#referD…