Java锁擦除与锁粗化概念和使用详解
作者:每天都要进步一点点 发布时间:2022-02-09 15:32:30
标签:Java,锁擦除,锁粗化
一、什么是锁擦除
锁擦除是指虚拟机即时编译器(JIT)在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行擦除。锁擦除的主要判定依据来源于逃逸分析的数据支持,如果判断在一段代码中,堆上的所有数据都不会逃逸出去从而被其他线程访问到,那就可以把它们当做栈上数据对待,认为它们是线程私有的,同步加锁自然就无须进行。
二、锁擦除的演示
public class LockErasureDemo {
public static void main(String[] args) {
new Thread(() -> {
String contact = contact("aa", "bb", "cc");
System.out.println(Thread.currentThread().getName() + ":" + contact);
}, "t1").start();
new Thread(() -> {
String contact = contact("dd", "ee", "ff");
System.out.println(Thread.currentThread().getName() + ":" + contact);
}, "t2").start();
}
private static String contact(String s1, String s2, String s3) {
StringBuffer stringBuffer = new StringBuffer();
return stringBuffer.append(s1).append(s2).append(s3).toString();
}
}
观察上面的代码,我们都知道StringBuffer的append方法是加了synchronized的同步方法:
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
这里锁住的对象其实就是stringBuffer这个局部变量,因为是局部变量,所以每个线程进来生成的stringBuffer对象不同,相当于每个线程自己new了一把锁,所以这里不存在竞争同一把锁的问题,JVM底层会将这个锁进行擦除。
三、什么是锁粗化
原则上,我们在编写代码的时候,总是推荐将同步块的作用范围限制得尽量小,只在共享数据的实际作用域中才进行同步,这样是为了使得需要同步的操作数量尽可能变小,如果存在锁竞争,那等待锁的线程也能尽快拿到锁。大部分情况下,上面的原则都是正确的,但是如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。
四、锁粗化的演示
public class LockCoarseningDemo {
static Object objLock = new Object();
public static void main(String[] args) {
// 反复加锁、解锁
new Thread(() -> {
synchronized (objLock) {
System.out.println("a");
}
synchronized (objLock) {
System.out.println("b");
}
synchronized (objLock) {
System.out.println("c");
}
}, "t1").start();
}
}
观察上面的案例,同一个线程对同一把锁,反复不断地获取锁、释放锁,这样肯定影响性能。为了避免重复的加锁解锁,JVM可能会将上面的代码优化成下面这样:
// 锁粗化: 如果方法中首尾相接,前后相邻的都是同一个锁对象,那JIT编译器就会把这几个synchronized块合并成一个大块
// 加粗加大范围,一次申请锁即可,避免多次的申请和释放锁,提升性能
new Thread(() -> {
synchronized (objLock) {
System.out.println("a");
System.out.println("b");
System.out.println("c");
}
}, "t1").start();
来源:https://weishihuai.blog.csdn.net/article/details/126579590


猜你喜欢
- 1.导入System.Runtime.InteropServices命名空间。2.API函数ShowWindow()能够控制人和窗体的现实状
- 概述SpringMVC的处理器 * 类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦
- 在页面提交到tomcat乱码 解决方法是在tomcat/conf/server.xml中进行配置以tomcat6.0.32为例,需将以下代码
- 概述最关键的区别是AlertDialog不能指定显示位置,只能默认显示在屏幕最中间(当然也可以通过设置WindowManager参数来改变位
- 本文实例讲述了java编程实现基于UDP协议传输数据的方法。分享给大家供大家参考,具体如下:UDP协议(User Datagram Prot
- 前言我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢。如果懂得了JVM的运行原理和内
- RecyclerView为什么会卡RecyclerView作为v7包的新控件,自从推出就广受Android Developer们欢迎,实际上
- 1.App的启动流程,从startActivity到Activity被创建。这个流程主要是ActivityThread和ActivityMa
- 如何使用exe4j把jar打包成exe文件最近,做了几个javafx的项目,想要把jar包打成exe的可执行软件,下面时我使用exe4j打包
- 1、原来是将EditView放到了popupwindow,发现EditView原有的复制、粘贴、全选、选择功能失效了,所以便用DialogF
- 本文实例讲述了C#实现图片切割的方法。分享给大家供大家参考,具体如下:图片切割就是把一幅大图片按用户要求切割成多幅小图片。dotnet环境下
- 框架的概述JDBC存在的问题:我们要想研究mybatis就必须知道jdbc所存在的问题,那我那么我们首先来复习一下jdbc操作数据库的大致流
- 原生系统Android8.1上,WiFi上出现感叹号,此时WiFi可正常访问。原因这是Android 5.0引入的网络评估机制:就是当你连上
- 1.springBoot的依赖确定项目中包含可以注解的依赖<dependency> <group
- git仓库直达List<String> strings = Lists.newArrayList("name=kk&q
- CountDownLatch 是一个同步工具类,用来协调多个线程之间的同步,它能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。
- 示例【通过班级查询老师信息】创建t_classes创建t_classessTeacher创建t_teacher创建Classespackag
- Android 自定义dialog的实现代码搜索相关关键字网上一大堆实现,但是看完总觉得缺胳膊少腿,绕了不少弯路,终于弄好了自定义dialo
- 1.首先是屏蔽浏览器右键菜单的问题,用以下代码可以让浏览器用自己的右键菜单:tempBrowser.ContextMenuStrip = t
- 快速普及1、mybatis是什么 mybatis是一个支持普通SQL查询,存储过