【JVM】JMM 内存模型

JMM

概述

内存模型

  1. java[内存模型](Java Memory Model) 和 [内存结构]
  2. JMM规定了在多线程下对共享数据的读写时,对数据的原子性 有序性 可见性的规则和保障。

原子性

  1. 原子性问题:

在这里插入图片描述

i++和i–不是原子性操作! 所以一个i++指令会在执行过程中被另一个线程执行!
在这里插入图片描述

  1. 问题分析:

在这里插入图片描述

(1)共享的变量信息是放在主内存中的,线程呢是在工作内存中
多线程情况下指令交错产生的问题:
在这里插入图片描述

  1. 问题解决
    java中通过synchronized来保证了原子性

在这里插入图片描述

EntryList: 排队等候区:阻塞住

Owner: 有一个一个线程可以进入成为owner

monitorExit: 表示owner中线程执行完毕,会通知EntryList中等待的线程。然后就可以拥有抢夺owner的机会,当等待的线程成为owner后就会执行monitorenter 锁住monitor区域

WaitSet: 是线程wait() notify()的时候需要用到的区域

在这里插入图片描述

优化:
在这里插入图片描述

Java锁机制

64位开启指针压缩为例:

在这里插入图片描述

  1. java中锁的实现:每个对象都拥有一把锁,该锁存放在对象头中。锁中记录了当前对象被哪个线程所占用。

在这里插入图片描述

在这里插入图片描述

  1. 对象的结构

    1. 对象头:(存放了一些对象本身的运行时信息)
      1. Mark Word:存储了很多和当前对象运行时状态有关的数据。
      2. Class Pointer: 指向了堆中当前类class对象。
    2. 实例数据:属性 + 方法
    3. 对齐填充字节: 为了满足对象的大小为8个字节的倍数,无实际意义。
  2. 锁状态:对象头的Mark Word中"锁标志位"分别对应四种锁状态:无锁、偏向锁、轻量级锁、重量级锁

  3. synchronized(重量级锁)实现线程同步:

    • 通过生成的monitorenter和monitorexit来实现同步。结合monitor区域来实现线程同步。

synchronized 缺点:本质:通过线程状态的切换。用户态<–>内核态,所以很慢。

synchronized 编译后是通过jvm指令monitorenter和monitorexit来实现同步,而该jvm指令实际上依赖操作系统的mutex lock来实现的。java线程实际上是对操作系统线程的映射,所以每当挂起/唤醒一个线程,都要从"用户态"切换。操作系统的"内核态",这种操作是比较重量级的!一些情况下甚至切换时间本身会超过线程执行任务的时间!所以使用synchronized会对性能产生严重的影响!

jdk 6后,对synchronized进行了优化,引入了无锁、偏向锁、轻量级锁

  • 对应了对象头Mark Word中的四种状态[无锁 偏向锁 轻量级锁 重量级锁]

注意锁只能升级不能降级!

synchronized 优化

synchronized是如何优化的?四种状态如何变化的?

  1. 无锁:线程都可以来访问该资源

    1. 无竞争
    2. 存在竞争.可以通过非锁方式,同步线程。失败重试(乐观锁思想)
      • CAS: Compare And Swap:CAS在操作系统中通过一条指令来实现,所以能够保证原子性!
        且在标价和交换的过程中,必须是原子性。不然两个线程就会抢到一个资源!
      • cas和锁的区别:
        • 锁: 通过锁定资源的方式,保证线程同步。给对象加锁。
        • cas: 通过别的方式,不锁定资源。
  2. 偏向锁:

    1. 对象能够认识这个线程,这个线程来了直接把锁交出去,认为对象偏向这个线程。
    2. 在偏向锁状态时通过线程ID来确定当前想要获得对象锁的线程。
    3. 当有多个线程来竞争这把锁,偏向锁会升级为轻量级锁。
    4. 使用场景:只有一个线程来获取资源,单线程。
  3. 轻量级锁:这时线程会在虚拟机栈中开辟一块被称为Lock Record的空间,线程通过cas获取锁,一旦获取到锁,会复制该对象的mark Word,并且将Lock Record中的owner指针指向该对象,该对象的对象头的Mark Word的前30个bit也会指向栈中锁记录的指针,这就实现了对象与线程的绑定。

在这里插入图片描述

这时候也有其他线程想要获取该对象该怎么办?

  • 自旋等待:线程自己在不断的轮询循环,尝试着看一下目标对象的锁有没有被释放。
  • 这种方式区别于被操作系统挂起,因为对象的锁很快被释放的话,自旋就不需要系统中断和现场恢复。所以效率高一些。
  • 自旋相当于cpu在空转,如果时间过长会占用资源。
  • 如果自旋等待的线程数超过1个,那么轻量级锁会升级为重量级锁。
  1. 如果对象头中锁状态被标记为重量级锁,那么需要通过monitor来对线程进行控制。

    此时将会完全锁定资源,此时的管控也最为严格.

在这里插入图片描述

轻量级锁和重量级锁的区别:

  1. 重量级锁:通过monitor来控制线程同步,等待的线程会进入阻塞状态。涉及用户态到内核态的转变,这属于比较重量级的操作。
  2. 轻量级锁:通过等待的线程进行自旋的方式进行等待,不会阻塞。

CAS

  1. 不锁定资源,也能同步线程
  2. 预期原值与新值
    • 预期原值: 之前读到的资源对象的状态值
    • 新值: 想要将预期原值更新后的值
    • 内存位置: 资源本身当前的值(资源的状态值)
  3. 比较
    • 比较预期原值和内存位置(资源的状态值),一致的话将内存位置改为新值。这样别的线程的预期原值和内存位置就不一样了,就不操作了。
  4. 核心问题
    • "比较数值,并进行值的更新"这个操作必须是原子的!不然会出问题!!会有两个线程同时抢到…同时只能有一条线程进行操作!!!
  5. 如何实现CAS的原子性?
    • CAS在操作系统中就是一条指令,所以是原子性的。

CAS: 乐观锁。本质是一种无锁的同步机制。Java底层是通过Unsafe的方法实现CAS操作。

可见性

volatile: 一个线程写,多个线程读的场景,无法保证原子性。

一. 可见性问题

在这里插入图片描述

二. 可见性问题分析

线程t1对于t2修改后的值不清楚的原因是,t1线程频繁的读取boolean这个变量。然后即时编译器就会视为热点代码。将boolean的值缓存到高速缓存中。所以t1每次读取都是从自己的工作内存中读取。主内存中改了值,其实t1线程是感知不到的。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

synchronized 和 volatile 比较

  • synchronized 关键字用于给代码块上锁,volatile用于修饰成员变量/静态变量
  • synchronized 既可以保证原子性,也可以保证可见性。但是属于重量级的操作,是一种重量级锁,线程的用户态->内核态的转变。
  • volatile可以保证可见性和有序性,但是不能保证原子性。通过读写屏障保证线程之间的
    可见性和禁止编译器/处理器对指令进行指令重排序!

有序性

volatile保证了禁止指令重排序。

有序性的理解

  1. 单线程情况下jvm对其指令重排是不太影响结果的。(指令重排是一种优化)
  2. 多线程下指令重排就会产生一些问题!

单例模式下双重锁机制的变量需要加volatile,否则会指令重排。使得返回的对象不完整

在这里插入图片描述

在这里插入图片描述

happens-before

规定了哪些写操作可以对其他线程的读操作可见,是可见性与有序性的一套规则:

在这里插入图片描述

在这里插入图片描述

CAS

一. 概述

在这里插入图片描述

CAS是与volatile配合使用的一项技术。体现的是一种乐观锁的思想,是一种无锁并发技术。

compareAndSwap:如果旧值和共享变量相同,则进行swap,把共享变量改为结果。

CAS适用场景

  1. 竞争不激烈,多核CPU的情况下。因为等待的线程并不是进入阻塞状态,而是一种在尝试尝试。其他线程也需要占用CPU资源。如果竞争激烈,会影响效率!
  2. 获取"主内存中的值时",为了保证变量的可见性,需要使用volatile来修饰!结合CAS和volatile可以实现无锁并发!
  3. synchronized的比较:
    • 该种并发技术并不会使等待的线程进入阻塞状态,而是通过不断尝试的方式来操作。但是当竞争激烈时,等待的线程会占用过多CPU资源,导致效率下降!
    • CAS操作底层依赖于一个Unsafe类直接调用操作系统底层的CAS指令。

二. 底层实现

CAS操作底层依赖于一个Unsafe类直接调用操作系统底层的CAS指令。

三. 原子操作类

  • java中的悲观锁:synchronized
  • java中的乐观锁:CAS

在这里插入图片描述

在这里插入图片描述

锁膨胀

在这里插入图片描述

自旋锁:自旋是一种在重量级锁上的优化,并不会让等待的线程进入阻塞状态,而是处于一种
自旋重试的操作!

在这里插入图片描述

其他优化

  1. 缩少锁的粒度:
    1. ConcurrentHashMap: 原来HashTable是锁住了整个数组,ConcurrentHashMap是给数组(每个链表头)进行加锁,也就是分段的机制,当前段的上锁,不影响其他段的读写操作!

JMM总结

在这里插入图片描述

  1. Java中锁的实现

每个对象都拥有一把锁,该锁存放在对象头中。锁中记录了当前对象被哪个线程所占用。

  1. 对象的结构
  • 对象头:存放了一些对象本身的运行时信息,包括两部分:
    • Mark Word: 存储了很多和当前对象运行时状态有关的数据。
    • Class Pointer: 指向了堆中当前类class对象。
  • 实例数据: 属性 + 方法
  • 对齐填充字节: 为了满足对象的大小为8个字节的倍数,无实际意义。
  1. 锁状态

对象头的Mark Word中"锁标志位"分别对应四种锁状态:

无锁01、偏向锁01、轻量级锁00、重量级锁10

  1. synchronized (重量级锁) 实现线程同步

通过生成的monitorentermonitorexit来实现同步。

synchronized的缺点:本质上是通过线程状态的切换,用户态<–>内核态,所以很慢。synchronized编译后是通过JVM指令monitorentermonitorexit来实现同步,而这些JVM指令实际上依赖操作系统的mutex lock来实现的。Java线程实际上是对操作系统线程的映射,所以每当挂起/唤醒一个线程,都要从"用户态"切换操作系统的"内核态",这种操作是比较重量级的!一些情况下甚至切换时间本身会超过线程执行任务的时间!所以使用synchronized会对性能产生严重的影响!

monitor区域…

在这里插入图片描述

从JDK 6后,对synchronized进行了优化,引入了无锁,偏向锁,轻量级锁。

注意,锁只能升级不能降级!

synchronized 优化

synchronized是如何优化的?四种状态如何变化的?

  1. 无锁:线程都可以来访问该资源

    1. 无竞争

    2. 存在竞争.可以通过非锁方式,同步线程。失败重试(乐观锁思想)

      • CAS: Compare And Swap:CAS在操作系统中通过一条指令来实现,所以能够保证原子性!
        且在标价和交换的过程中,必须是原子性。不然两个线程就会抢到一个资源!

      • cas和锁的区别:

        • 锁: 通过锁定资源的方式,保证线程同步。给对象加锁。
        • cas: 通过乐观锁思想方式,不锁定资源。
  2. 偏向锁

    • 对象能够认识这个线程,这个线程来了直接把锁交出去,认为对象偏向这个线程。称为偏向锁。
    • 在偏向锁状态时通过线程ID来确定当前想要获得对象锁的线程。
    • 当有多个线程来竞争这把锁,偏向锁会升级为轻量级锁。
    • 使用场景: 只有一个线程来获取资源。单线程。
  3. 轻量级锁在这里插入图片描述

    • 这时线程会在虚拟机栈中开辟一块被称为Lock Record的空间。
    • 线程通过CAS获取锁,一旦获取到锁,会复制该对象的Mark Word,并且将Lock Record中的owner指针指向该对象,该对象的对象头的Mark Word的前30个bit也会指向栈中锁记录的指针,这就实现了对象与线程的绑定。
    • 这时候也有其他线程想要获取该对象该怎么办?
      • 自旋等待: 线程自己在不断的轮询循环,尝试着看一下目标对象的锁有没有被释放。
      • 如果自旋等待的线程数超过1个,那么轻量级锁会升级为重量级锁。
      • 锁膨胀: 竞争的线程想要通过CAS操作获取共享对象的锁的时候,获取不到。就会进行锁膨胀,转化为重量级锁!
  4. 重量级锁

    • 如果对象头中锁状态被标记为重量级锁,那么需要通过monitor来对线程进行控制…
      • 此时将会完全锁定资源,此时的管控也最为严格。

轻量级锁和重量级锁的区别:

  1. 重量级锁:通过monitor来控制线程同步,等待的线程会进入阻塞状态。涉及用户态到内核态的转变,这属于比较重量级的操作。
  2. 轻量级锁:通过等待的线程进行自旋的方式进行等待,不会阻塞。

CAS

  1. 不锁定资源,也能同步线程
  2. 预期原值与新值
    • 预期原值: 之前读到的资源对象的状态值
    • 新值: 想要将预期原值更新后的值
    • 内存位置: 资源本身当前的值(资源的状态值)
  3. 比较
    • 比较预期原值和内存位置(资源的状态值),一致的话将内存位置改为新值。这样别的线程的预期原值和内存位置就不一样了,就不操作了。
  4. 核心问题
    • "比较数值,并进行值的更新"这个操作必须是原子的!不然会出问题!会有两个线程同时抢到。同时只能有一条线程进行操作!
  5. 如何实现CAS的原子性?
    • CAS在操作系统中就是一条指令,所以是原子性的。

CAS: 乐观锁。本质是一种无锁的同步机制 + volatile。Java底层是通过Unsafe的方法实现CAS操作。

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

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

相关文章

牛客美团2024年春招第一场笔试【技术】解题

1.小美的平衡矩阵 小美拿到了一个n∗n的矩阵&#xff0c;其中每个元素是 0 或者 1。 小美认为一个矩形区域是完美的&#xff0c;当且仅当该区域内 0 的数量恰好等于 1 的数量。 现在&#xff0c;小美希望你回答有多少个i∗i的完美矩形区域。你需要回答1≤i≤n的所有答案 输出…

VSCode连接远程服务器时卡在审核(check)log.txt和pid.txt

诸神缄默不语-个人CSDN博文目录 VSCode就NM跟SB一样天天搁那儿更新&#xff0c;瞎JB更新&#xff0c;每次更新都要出一次兼容性问题&#xff0c;远程服务器不能连公网就上不去了&#xff0c;也没有显式提示&#xff0c;错误很明显就是在下载不了文件&#xff0c;用VSCode内置的…

Linux的有关权限的学习

1.认识权限在Linux中的表示 在Linux中&#xff0c;一切皆文件&#xff0c;而每个文件都会有其相对应的操作权限。那么&#xff0c;我们该怎么来认识他们呢&#xff1f; 首先我们可以看到&#xff0c;在每个test文件的前面都会有一个-rw-r--r--这个字符&#xff0c;而这个字符&…

ServiceNow 研究:通过RAG减少结构化输出中的幻觉

论文地址&#xff1a;https://arxiv.org/pdf/2404.08189 原文地址&#xff1a;rag-hallucination-structure-research-by-servicenow 在灾难性遗忘和模型漂移中&#xff0c;幻觉仍然是一个挑战。 2024 年 4 月 18 日 灾难性遗忘&#xff1a; 这是在序列学习或连续学习环境中出现…

Pycharm远程环境开发(保姆级详细步骤)

使用远程机器的python环境 同步一下linxu和window的文件 可以从远端下载到本地(如下图所示)&#xff0c;也可以从本地上传到linux&#xff0c;在左侧的目录里右键选择你所需要的上传文件点击deployment然后upload就行

k8s 资源组版本支持列表

1 kubernetes的资源注册表 kube-apiserver组件启动后的第一件事情是将Kubernetes所支持的资源注册到Scheme资源注册表中,这样后面启动的逻辑才能够从Scheme资源注册表中拿到资源信息并启动和运行API服务。 kube-apiserver资源注册分为两步:第1步,初始化Scheme资源注册表;…

Linux进程——Linux下常见的进程状态

前言&#xff1a;在进程学习这一块&#xff0c;我们主要学习的就是PCB这个进程控制块&#xff0c;而PBC就是用来描述进程的结构体&#xff0c;而进程状态就是PCB结构体中的一个变量。 本篇主要内容&#xff1a; 操作系统中的进程状态Linux下的进程状态 在开始之前&#xff0c;我…

AI学习指南-人工智能概述

欢迎来到人工智能的奇妙世界&#xff01;如果你是初学者&#xff0c;那么你来对地方了。今天&#xff0c;我们将一起探索人工智能&#xff08;AI&#xff09;的基本概念&#xff0c;看看它是如何分类的&#xff0c;它的应用有哪些&#xff0c;以及未来可能的发展方向。准备好了…

每日一题(力扣740):删除并获得点数--dp+思维

其实跟打家劫舍没啥区别 排序去重之后去考虑当前位置和前两个位置之间的关系即可&#xff0c;具体见代码&#xff1a; class Solution { public:int deleteAndEarn(vector<int>& nums) {int n nums.size();if (n 1) return nums[0];unordered_map<int, int>…

Java项目:基于SSM框架实现的在线医疗服务系统(ssm+B/S架构+源码+数据库+毕业论文+开题报告)

一、项目简介 本项目是一套基于SSM框架实现的在线医疗服务系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

MES(制造执行系统)与PDCA循环,斩不断理还乱的关系。

MES系统算是B端系统中比较复杂的一种&#xff0c;这与我国制造业标准化程度较低有一定的关联&#xff0c;MES的存在就是要更好执行PDCA循环&#xff0c;二者关联是千丝万缕的&#xff0c;B系统提升专家借此为大家分享一下。 一、什么是PDCA PDCA&#xff08;Plan-Do-Check-Ac…

【系统架构师】-选择题(十一)

1、紧耦合多机系统一般通过&#xff08;共享内存&#xff09;实现多机间的通信。对称多处理器结构&#xff08;SMP&#xff09;属于&#xff08; 紧耦合&#xff09;系统。 松耦合多机系统又称间接耦合系统,—般是通过通道或通信线路实现计算机间的互连。 2、采用微内核的OS结构…

SQLite如何处理CSV 虚拟表(三十七)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite的DBSTAT 虚拟表&#xff08;三十六&#xff09; 下一篇:SQLite的扩展函数Carray()表值函数(三十八) ​ RFC4180格式是一种文本文件格式&#xff0c;被用于表格数据间的交互&#xff0c;也可将表格数据转化…

项目管理-项目范围管理1/2

1.项目范围管理-知识框架 2.范围管理-6个过程 项目范围管理&#xff0c;过程 6个&#xff0c;包括“规收定 创确控”&#xff1a; 规划范围管理收集需求定义范围创建WBS确认范围控制范围 2.1规划范围管理 &#xff08;1&#xff09;主要内容 4-3-2 &#xff08;2&#xf…

如何低成本创建个人网站?

目录 前言 网站源代码 虚拟主机或服务器 域名注册或免费二级域名 域名解析 上传源代码压缩包 添加刚刚的域名 成功搭建 失败的解决方案 结语 前言 很多小白都非常想拥有自己的网站&#xff0c;但很多人虽然有了自己的源代码但苦于不知道怎么将其变成所有人都能够访…

Lucene从入门到精通

**************************************************************************************************************************************************************************** 1、概述 【1】入门&#xff1a;作用、有点与缺点 【2】应用&#xff1a;索引、搜索、fie…

Redis Zset的底层原理

Redis Zset的底层原理 ZSet也就是SortedSet&#xff0c;其中每一个元素都需要指定一个score值和member值&#xff1a; 可以根据score值排序后member必须唯一可以根据member查询分数 因此&#xff0c;zset底层数据结构必须满足键值存储、键必须唯一、可排序这几个需求。之前学…

Java | Leetcode Java题解之第66题加一

题目&#xff1a; 题解&#xff1a; class Solution {public int[] plusOne(int[] digits) {int n digits.length;for (int i n - 1; i > 0; --i) {if (digits[i] ! 9) {digits[i];for (int j i 1; j < n; j) {digits[j] 0;}return digits;}}// digits 中所有的元素…

LeetCode 131 —— 分割回文串

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 首先&#xff0c;按照 LeetCode 5——最长回文子串 中的思路&#xff0c;我们先求出 d p dp dp&#xff0c;这样我们就知道了所有的子串是否是回文子串。 然后&#xff0c;我们进行一个 dfs 搜索&#xff0c;起…

计算机网络4——网络层6路由器构成

文章目录 一、路由器的构成1、路由器结构2、交换结构 二、IP多播1、IP多播的概念2、在局域网上进行硬件多播 三、网际组管理协议IGMP和多播路由选择协议1、IP 多播需要两种协议2、网际组管理协议 IGMP3、多播路由选择协议 一、路由器的构成 1、路由器结构 路由器是一种具有多…