JVM学习-JMM

目录

1.什么是JMM

2.JMM怎样保障数据的可见性、有序性、原子性

        2.1保证原子性

        2.2.保证可见性

        2.3保证有序性

3.CAS

        3.1乐观锁和悲观锁

        3.2 CAS介绍

4.重量级锁的自旋优化


1.什么是JMM

        JMM即Java内存模型 ,定义了一套在多线程读写共享数据(如数组、成员变量等)时,对数据的可见性、有序性、原子性的规则和保障。JMM和Java内存结构关系不大,内存结构就是JVM的内存组成、垃圾回收以及字节码和类加载的一些技术。

2.JMM怎样保障数据的可见性、有序性、原子性

        2.1保证原子性

        对于多个线程共享的数据而言,如果不对数据进行加锁,那么多个线程在调用同一资源时很可能出现异常操作。

        比如线程1和线程2分别对一个初始值为0的变量 i 执行 i++ 和 i-- 操作,理论上执行的结果是0,但实际情况却不一定。由于操作系统在处理线程时采用的是时间片轮转的方式,很有可能出现线程1还未执行完 i++ 时间片就耗尽了,接下来就轮到线程2执行 i-- 操作。线程2在时间片内完成了对 i 的修改,此时 i 的值为-1。然后再次轮到线程1,由于线程1拿到的 i 的初始值是0,所以 i++ 是在 i=0 的基础上执行的,执行完成后 i 的值为1,覆盖掉了线程2的执行结果-1,所以相当于线程2对于 i 的修改是无效的。

        这就需要进行加锁,当一个线程对一个共享资源未使用完毕前其他线程不能使用这一资源,也就是保障了对共享资源的操作在执行完之前不会有其他线程访问这一资源。
        加锁操作:

synchronized(要加锁的对象){需要保障原子性的代码
}

        锁粗化:在加锁时要尽量扩大加锁的范围,比如对变量 i 执行一千次加1操作,如果仅对加一的操作进行加锁,那么就会执行一千次加锁和解锁的操作;但如果是对整个循环进行加锁,不仅可以保证原子性,而且只用执行一次加锁和解锁的操作,能够缩短运行时间。

        2.2.保证可见性

        共享资源存储在主内存中,当一个线程频繁读取某一资源时JIT(即时编译器)会进行优化,将该资源的值存入到该线程工作内存中的高速缓存中,后面再读取这个资源的值时会从这个高速缓存中读取,虽然提高了效率,但当对这一资源的值进行修改后,还是会从高速缓存中读取之前的旧值,导致线程对这个资源的修改不可见。
        有两种方式保证可见性:

  • 使用synchronized加锁

        在加锁时会清空工作内存中对所有共享资源的缓存,强制要求到主内存中重新读取共享变量的值,保证了拿到的共享变量的值是最新的。并且在解锁时,无论是否对共享变量的值进行了修改,都会将共享变量的值刷新回主内存,以确保主内存中的共享变量的值是最新的。也可以直接调用System.out.println(),因为执行输出操作时会调用到synchronized。

        优点是既能确保原子性又能确保可见性,缺点就是synchronized属于重量级的操作,性能较低。

  • 使用volatile关键字

        对共享变量加上volatile关键字能够强制要求线程在读取共享变量的值时总是从主内存中读取,保证了可见性。该方式性能较高,但仅适用于一个写线程其他都是读线程的情况,因为如果有多个写线程由于不能保证原子性就无法确定拿到的值是否是正确的。

        2.3保证有序性

        JVM在执行赋值操作时会根据指令是否耗时而进行指令重排,在不影响结果的条件下调整指令的执行顺序,但在并发执行时更改指令的执行顺序就可能会出现错误,此时可以通过加上volatile关键字禁用指令重排来保证有序性。

3.CAS

        3.1乐观锁和悲观锁

        在介绍CAS之前先来了解一下乐观锁和悲观锁:

        3.2 CAS介绍

        CAS即Compare And Swap,是一种乐观锁的思想,不使用synchronized对共享变量加锁,通过volatile关键字的配合实现了无锁并发。原理是通过一个while循环不断尝试修改共享变量的值,在循环时暂时存储该共享变量的原值和本线程修改后的值,并通过compareAndSwap方法来判断该线程修改共享变量结束后存储的原值是否和当前共享变量的值相同。如果不同说明在该线程修改共享变量期间其他线程对共享变量的值进行了修改,那么本次修改就是无效的,需要再次进入循环重新获取共享变量的值并尝试修改;如果相同说明修改期间其他线程并没有对共享变量进行修改,那么就会将修改的结果更新到主内存中,并返回true,可以通过if语句实现跳出循环。

        至于要volatile关键字的配合是因为要保证可见性,在每次循环时都能获取到共享变量最新的值。
        由于synchronized加锁会使线程进入阻塞,并进行上下文切换,需要保存线程阻塞前的状态并在被唤醒时恢复,这一过程是非常耗时的,所以CAS无锁并发能够提升效率;但CAS适用于线程竞争不激烈并且是多核CPU的情况下,因为当竞争比较激烈时肯定会进行频繁的循环,此时就需要花费大量的时间来不断尝试修改共享变量的值;而如果是单核CPU,那么当时间片耗尽时只能等待下次拿到时间片时才能继续尝试,但多核CPU就能实现在其他线程运行的同时不断尝试,这才能体现CAS的优势。

4.重量级锁的自旋优化

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

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

相关文章

openssl3.2 - note - Writing OpenSSL Provider Skeleton

文章目录 openssl3.2 - note - Writing OpenSSL Provider Skeleton概述笔记测试工程的建立复现的provider工程总结Provider包含的头文件openssl/core.h中的数据结构实现 OSSL_provider_init()看一下openssl自带的提供者provider的openssl命令行测试provider的本质是hook了opens…

插入排序:一种简单而有效的排序算法

插入排序:一种简单而有效的排序算法 一、什么是插入排序?二、插入排序的步骤三、插入排序的C语言实现四、插入排序的性能分析五、插入排序的优化六、总结 在我们日常生活和工作中,排序是一种非常常见的操作。比如,我们可能需要对一…

【 c 语言 】指针入门

🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:C语言 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步&…

ChatGPT编程—实现小工具软件(文件查找和筛选)

ChatGPT编程—实现小工具软件(文件查找和筛选) 今天借助[小蜜蜂AI][https://zglg.work]网站的ChatGPT编程实现一个功能:根据特定需求结合通配符和其他条件来进行文件查找和筛选。在这个例子中,我们将创建一个函数find_files,它接受用户输入的…

RK3568平台开发系列讲解(基础篇)内核是如何发送事件到用户空间

🚀返回专栏总目录 文章目录 一、相关接口函数二、udevadm 命令三、实验沉淀、分享、成长,让自己和他人都能有所收获!😄 一、相关接口函数 kobject_uevent 是 Linux 内核中的一个函数, 用于生成和发送 uevent 事件。 它是 udev 和其他设备管理工具与内核通信的一种方式。…

【Spring Boot】创建你的第一个 Spring Boot 应用

创建你的第一个 Spring Boot 应用 1.环境配置2.步骤详解3.项目结构分析3.1 入口类 DemoApplication3.2 控制器 PathVariableController3.3 控制器 BasicController3.4 模型 User 4.运行 Spring Boot 目前已经成为了 Java 开发领域的框架范式。本篇博客,我将带领大家…

layui table列表重载后保持进度条位置不变

使用layui的table表格组件时,当我们操作了某行的修改后,刷新了页面,进度条则跳回到最上面。 除了layui高版本应该内置有方法解决了此问题,但是低版本需要另外想办法解决。 具体解决方式如下: 1.在编辑操作成功前&am…

【MASM汇编语言快速入门】8086MASM汇编深入理解指令对标志位的影响

8086MASM汇编深入理解指令对标志位的影响 文章目录 8086MASM汇编深入理解指令对标志位的影响0. 指令对标志位影响1. 指令对标志位影响速查表2. flags标志寄存器: 标志位含义解读flags1. 状态标志cf, pf, af, zf, sf, of2. 控制标志df, if, tf 详解:1. 传送指令2. 算…

如何在IDEA 中设置背景图片

在IDEA 中设置背景图片,可以按照以下步骤操作: 1、打开 IntelliJ IDEA 软件,进入代码编辑主界面。 点击编辑窗口上方的“File”菜单项。 2、在下拉子菜单中,选择“Settings”选项(如果你使用的是 macOS,可…

Spark-Scala语言实战(1)

在之前的文章中,我们学习了如何在Linux安装Spark以及Scala,想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下你宝贵的点赞,谢谢。 Spark及Scala的安装https:/…

【智能算法】保姆级教程-如何使用CEC测试集,以及如何定义自己的优化问题

目录 1.准备工作2.使用CEC2005测试集3.自定义优化问题-无约束问题4.自定义优化问题-有约束问题5.代码实现 1.准备工作 一个CEC2005测试集 一个测试智能算法,比如麻雀搜索算法SSA 2.使用CEC2005测试集 以CEC2005测试集函数F7为例: 3.自定义优化问题…

solr/ES 分词插件Jcseg设置自定义词库

步骤: 1、找到配置文件jcseg-core/target/classes/jcseg.properties修改配置: 下载地址: https://gitee.com/lionsoul/jcseg#5-如何自定义使用词库 lexicon.path {jar.dir}/../custom-word 设置lexicon路径,我们这个配置可以自定义&#xf…

计算机网络-概述

文章目录 1.2 因特网概述1.2.1 网络、互连网(互联网)和因特网1.2.2 因特网发展的三个阶段1.2.4 因特网的组成 1.3 三种交换方式1.3.1 电路交换1.3.2 分组交换1.3.3 报文交换1.3.4 三种方式对比 1.4 计算机网络的定义1.5 计算机网络的性能指标1.5.1 速率1…

antd5 虚拟列表原理(rc-virtual-list)

github:https://github.com/react-component/virtual-list rc-virtual-list 版本 3.11.4(2024-02-01) 版本:virtual-list-3.11.4 Development npm install npm start open http://localhost:8000/List 组件接收 Props PropDescriptionTypeDefaultchildrenRender …

精读《手写 JSON Parser》

1 引言 JSON.parse 是浏览器内置的 API,但如果面试官让你实现一个怎么办?好在有人已经帮忙做了这件事,本周我们一起精读这篇 JSON Parser with Javascript 文章吧,再温习一遍大学时编译原理相关知识。 2 概述 & 精读 要解析…

【机器学习】分类模型的评价方法

🌻个人主页:相洋同学 🥇学习在于行动、总结和坚持,共勉! #学习笔记# 目录 一、混淆矩阵(Confusion Matrix) 二、评估指标(Evaluation metrics) 1.正确率(accuracy) …

R统计学3 - 数据分析入门问题41-60

往期R统计学文章: R统计学1 - 基础操作入门问题1-20 R统计学2 - 数据分析入门问题21-40 41. R 语言如何做双坐标图? # 创建模拟数据 year <- 2014:2024 gdp <- data.frame(year, GDP = sort(rnorm(11, 1000, 100))) ur <- data.frame(year, UR = rnorm(11, 5, 1…

计算机网络(7)----应用层

目录 一.应用层的基本概念 1.应用层的基本概述 2.网络应用模型 &#xff08;1&#xff09;客户/服务器模型 &#xff08;2&#xff09;P2P模型 二.应用程序相关 1.DNS系统 &#xff08;1&#xff09;域名与域名服务器 &#xff08;2&#xff09;域名解析过程&#xff…

2024 第一届VCTF 纳新赛 Web方向 题解WP

hackjs 题目描述&#xff1a;A baby oldjs, just warm up. 附件给源码 const express require(express) const fs require(fs) var bodyParser require(body-parser); const app express() app.use(bodyParser.urlencoded({extended: true })); app.use(bodyParser.json…

CI/CD实战-git工具使用 1

版本控制系统 本地版本控制系统 集中化的版本控制系统 分布式版本控制系统 git官网文档&#xff1a;https://git-scm.com/book/zh/v2 Git 有三种状态&#xff1a;已提交&#xff08;committed&#xff09;、已修改&#xff08;modified&#xff09; 和 已暂存&#xff08;sta…