面试题:JVM 对锁都进行了哪些优化?

文章目录

  • 锁优化
  • 自旋锁和自适应自旋
  • 锁消除
  • 锁粗化
  • 逃逸分析
  • 方法逃逸
  • 线程逃逸
  • 通过逃逸分析,编译器对代码的优化


锁优化

jvm 在加锁的过程中,会采用自旋、自适应、锁消除、锁粗化等优化手段来提升代码执行效率。

自旋锁和自适应自旋

现在大多的处理器都是多核处理器 ,如果在多核心处理器,有让两个或者以上的线程并行执行,我们可以让一个等待线程不放弃处理器的执行时间。设置一个等待超时时间,看线程是否能够很快的释放锁,在等等待的这段时间可以执行一个空循环,让当前线程继续占用 CPU 的时间片。这就是所谓的「自旋锁」。

JVM 中可以通过 +XX:UseSpinning来开启自旋锁,在 JDK1.6 过后默认为我们开启。由于自旋锁的使用会让锁的竞争者占用更多的处理器时间, JVM 规定了一个自旋次数的一个参数。我们可以通过 -XX:PreBlockSping来进行更改(默认10次)。

偏向锁、轻量级锁的状态转化及对象 Mark Word 的关系转换入下图所示:

图片

锁消除

锁消除是指虚拟机即时编译器在运行时检测到某段需要同步的代码不可能存在共享数据竞争而实施的一种对锁进行消除的优化策略。锁消除的主要判断依据于逃逸分析。如果判断一段代码,在堆上所有的数据都不会逃逸出去被别的线程访问到,那就把它当作栈上的数据对待,认为它们是私有的,同步加锁就无需进行。

下面是三个字符串 x, y, z 相加的例子,无论是从源代码上还是逻辑上都没有进行同步

public String concatStr(String x, String y, String z) {return  x + y + z;
}

String 是一个不可变的类,对字符的链接总是生成新的 String 对象来进行的,因此 Javac 编译器会对 String 链接进行自动优化,在 jdk5 之前字符串链接会转换为 StringBuffer;在 jdk5 之后会转换为 StringBuilder 对象连续的 append()操作,我们看看 javac 过后,反编译的结果:

public String concatStr(String x, String y, String z) {StringBuilder sb = new StringBuilder();sb.append(x);sb.append(y);sb.append(z);return  sb.toString();
}

我们再来看看 javap反编译的结果:

图片

javap反编译的结果

这里大家可能会担心 StringBuilder不是线程安全的的操作会存在线程安全的问题吗?这里的答案是不会,x + y + z操作的优化「经过逃逸分析」过后,他的动态作用域被限制在了 concatStr方法内,就是说当前实际执行的 StringBuilder 的操作在 concatStr 方法内部,「其他的外部线程无法访问」到,所以这里「虽然有锁,但是可以被安全的消除掉。所以当我们进行编译过后,这段代码就会忽略掉所有的同步措施直接执行。」

锁粗化

原则上,我们在写代码的时候,总是推荐将同步块的作用范围限制得尽可能的小–只在共享数据的实际操作作用域中才进行同步,这样也是为了使得需要同步的操作尽可能的变少,即使存在锁的竞争,等待的锁的线程也能很快的获取到锁。大多数情况下,上面的原则都是正确的,但是如果「一系列的连续操作都是对同一个对象反复加锁和解锁,甚至加锁操作时出现在循环体之中」的,那即使没有线程的竞争,频繁的进行相互操作也会导致不必需要的性能损耗

StringBuffer buffer = new StringBuffer();
/**  锁粗化 */
public void append(){buffer.append("aaa").append(" bbb").append(" ccc");
}

上面的代码每次调用 buffer.append 方法都需要加锁和解锁,如果 JVM 家册到有一串连续的对同一个对象加锁和解锁的操作,就会将其合并成一次范围更大的加锁解锁操作,即在第一个 append 方法执行的时候进行加锁,最后一个 append 方法结束后进行解锁。

逃逸分析

逃逸分析(Escape Analysis),是一种可能减少有效 Java 程序中同步负载和内存堆分配压力的跨全局函数数据流分析算法。通过逃逸分析, Java Hotspot 编译器能够分析出一个新的对象引用范围从而决定是否要将这个对象分配到堆上,「逃逸分析的基本行为就是分析对象的动态作用域。」

方法逃逸

当一个对象在方法里面被定义后,它可能被外部方法所引用,例如调用参数传递到其他方法中,这种称为方法逃逸。

线程逃逸

当一个对象可能被外部线程访问到,比如:赋值给其他线程中访问的实例变量,这种称为线程逃逸。

通过逃逸分析,编译器对代码的优化

如果能够证明一个对象不会逃逸到到方法外或线程外(其他线程方法或者线程无法通过任何方法访问该变量),或者逃逸程度比较低(只逃逸出方法而不逃逸出线程)则可以对这个对象采用不同程度的优化:

1、栈上分配(Stack Allocations)完全不会逃逸的局部变量和不会逃逸出线程的对象,采用栈上分配,对象就会跟随方法的结束自动销毁。以减少垃圾回收器的压力。

2、标量替换(Scalar Replacement)有个对象可能不需要作为一个连续的存储结果存储也能被访问到,那么对象的部分(或者全部)可以不存储在内存,而是存储在 CPU 寄存器中。

3、同步消除(Synchronization Elimination)如果一个对象发现只能在一个线程访问到,那么这个对象的操作可以考虑不同步。

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

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

相关文章

易点易动设备管理系统:解决企业设备管理难题的利器

在现代企业中,设备管理是一个至关重要的环节。无论是制造业、物流业还是服务业,设备的高效管理对于企业的运营和竞争力都至关重要。然而,许多企业在设备管理方面面临着各种挑战。为了解决这些难题,易点易动设备管理系统应运而生。…

[vue]Echart使用手册

[vue]Echart使用手册 使用环境Echart的使用Echart所有组件和图表类型Echart 使用方法 使用环境 之前是在JQuery阶段使用Echart,直接引入Echart的js文件即可,现在是在vue中使用,不仅仅时echarts包,还需要安装vue-echarts: "…

Pycharm解释器的配置: System Intgerpreter 、Pipenv Environment、Virtualenv Environment

文章目录 前提1. 环境准备2. 了解虚拟环境 一、进入Interpreter设置页二、添加Interpreter1. 方式一2. 方式二 三、 System Interpreter四、 Pipenv Environment前提条件:详细步骤1) 选择pipenv2) 设置Base Interpreter3) 设置Pip…

基于Java SSM框架实现人事员工考勤签到请假管理系统项目【项目源码+论文说明】

基于java的SSM框架实现人事员工考勤签到请假管理系统演示 摘要 在高速发展的时代,众多的软件被开发出来,给用户带来了很大的选择余地,而且人们越来越追求更个性的需求。在这种时代背景下,人们对人事管理系统越来越重视&#xff0…

css图片属性,图片自适应

CSS 图片属性指南:background-size 和 object-fit 在前端开发中,使用图片是非常常见的。为了让图片在网页中显示得更好,CSS 提供了多种属性来调整和控制图片的大小和布局。其中,background-size 和 object-fit 是两个常用的属性&a…

制作系统安装盘教程——烧录Windows原版镜像

前言 本次教程不经过WinPE工具进行安装Windows原版镜像,而是直接把系统镜像文件直接烧录进U盘,这样做的好处是不经过WinPE安装Win系统的过程,避免有些带木马病毒的WinPE在安装系统的过程把木马病毒带进系统,从而导致文件泄漏。 开…

【JavaWeb学习笔记】13 - JSP浏览器渲染技术

JSP 一、JSP引入 1.JSP现状 1.目前主流的技术是前后端分离(比如: Spring Boot Vue/React),我们会讲的.[看一下] 2. JSP技术使用在逐渐减少,但使用少和没有使用是两个意思,一些老项目和中小公司还在使用JSP,工作期间,你很有可能遇到JSP …

【设计模式-2.5】创建型——建造者模式

说明:本文介绍设计模式中,创建型设计模式中的最后一个,建造者模式; 入学报道 创建型模式,关注于对象的创建,建造者模式也不例外。假设现在有一个场景,高校开学,学生、教师、职工都…

12.21

一、注意事项 1.CtrlShiftT用于从jar中查找类,这个eclipse键盘快捷键可以帮助快速找到类 2.更新upm和rest遇到重复解决方法 把upm文件里面多出来的三行代码删掉,右击upm文件,点击小组,点击标记为已解决,点击OK&#x…

Web前端-JavaScript(对象)

文章目录 1.对象1.1 概念1.2 创建对象三种方式**对象字面量创建对象**:new Object创建对象构造函数创建对象 1.3 遍历对象 2.作用域1.1 概述1.2 全局作用域1.3 局部作用域1.4 JS没有块级作用域1.5 变量的作用域1.6 作用域链1.7 预解析 1.对象 1.1 概念 什么是对象 …

Solon 开源框架,单月下载突破 250 万!!!

Solon 是什么开源项目? 一个,Java 生态型应用开发框架。它从零开始构建,有自己的标准规范与开放生态(历时六年,已有全球第二级别的生态规模)。与其他框架相比,它解决了两个重要的痛点&#xff…

jetbrains idea 报错 java.lang.ClassNotFoundException 之后自动搜索包导入包

-- 搜索类所在的包 导入包 搜索包 mac环境 pom中右键或者 cmdn

shell 的错误处理和调试方法

简介 在我们写代码过程中,一般有两个阶段:调试阶段和试运行阶段。在调试阶段我们希望尽可能的输出日志,方便在出错的时候快速定位问题。在试运行阶段希望将日志标准化,且有些错误的日志是在预期内不想展示的时候如何处理&#xff…

1. 线程概述、线程和进程、 并发和并行、多线程的优势 、程序运行原理 、主线程、 线程的 6 种状态

文章目录 1. 线程概述1.1 线程和进程1.2 并发和并行1.3 多线程的优势1.4 程序运行原理1.5 主线程 1.6 线程的 6 种状态 1. 线程概述 1.1 线程和进程 ​ 进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位…

高校/企业如何去做数据挖掘呢?

随着近年来人工智能及大数据、云计算进入爆发时期,依托三者进行的数据分析、数据挖掘服务已逐渐成为各行业进行产业升级的载体,缓慢渗透进我们的工作和生活,成为新时代升级版的智能“大案牍术”。 那么对于多数企业来说,如何做数据…

将遗留系统分解为微服务:第 2 部分

在当今不断发展的技术环境中,从整体架构向微服务的转变对于许多企业来说都是一项战略举措。这在报销计算系统领域尤其重要。正如我在上一篇文章第 1 部分应用 Strangler 模式将遗留系统分解为微服务-CSDN博客中提到的,让我们探讨如何有效管理这种转变。 …

Kylin的工作原理及使用分享:构建大数据分析之塔

学习目标: 了解Kylin的工作原理和基本概念理解Kylin在大数据分析中的作用和价值学会使用Kylin进行数据建模、数据预处理和查询 学习内容: 什么是Kylin? Kylin是一个开源的分布式分析引擎,专注于大数据的实时多维分析。它能够通过…

Appium Server 启动失败常见原因及解决办法

Error: listen EADDRINUSE: address already in use 0.0.0.0:4723 如下图: 错误原因:Appium 默认的4723端口被占用 解决办法: 出现该提示,有可能是 Appium Server 已启动,关闭已经启动的 Appium Server 即可。472…

Alien Skin Exposure 7汉化破解版下载 V 7.1.0.214 中文注册版

软件介绍 Alien Skin Exposure 7是一款超好用的PS胶片效果调色滤镜,它为数码照片提供胶片的曝光,还包括模仿胶片的颗粒感,并且可以控制胶片颗粒的分布,能够帮助用户对图片进行更好的处理! 软件特色 1、支持RAW格式&a…

node-red:使用node-red-contrib-amqp节点,实现与RabbitMQ服务器(AMQP)的消息传递

node-red-contrib-amqp节点使用 一、简介1.1 什么是AMQP协议?1.2 什么是RabbitMQ? -> 开源的AMQP协议实现1.3 RabbitMQ的WEB管理界面介绍1.3 如何实现RabbitMQ的数据采集? -> node-red 二、node-red-contrib-amqp节点安装与使用教程2.1 节点安装2.2 节点使用2.2.1 amq…