首页 > 编程语言 >Java 锁粗化和锁消除

Java 锁粗化和锁消除

时间:2024-07-01 15:31:10浏览次数:14  
标签:同步 Java synchronized 代码 sBuf 粗化 消除 append

原文:Java 锁消除和锁粗化

锁粗化

通常情况下,为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽可能短,但是某些情况下,一个程序对同一个锁不间断、高频地请求、同步与释放,会消耗掉一定的系统资源,因为锁的请求、同步与释放本身会带来性能损耗,这样高频的锁请求就反而不利于系统性能的优化了,即使单次同步操作的时间可能很短。锁粗化就是告诉我们任何事情都有个度,有些情况下我们反而希望把很多次锁的请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗。

一种极端的情况如下:

public void doSomethingMethod(){
    synchronized(lock){
        // do some thing
    }
    // 这是还有一些代码,做其它不需要同步的工作,但能很快执行完毕
    synchronized(lock){
        // do other thing
    }
}

上面的代码是有两块需要同步操作的,但在这两块需要同步操作的代码之间,需要做一些其它的工作,而这些工作只会花费很少的时间,那么我们就可以把这些工作代码放入锁内,将两个同步代码块合并成一个,以降低多次锁请求、同步、释放带来的系统性能消耗,合并后的代码如下:

public void doSomethingMethod(){
    // 进行锁粗化:整合成一次锁请求、同步、释放
    synchronized(lock){
        // do some thing
        // 做其它不需要同步但能很快执行完的工作
        // do other thing
    }
}

注意:这样做是有前提的,就是中间不需要同步的代码能够很快速地完成,如果不需要同步的代码需要花很长时间,就会导致同步块的执行需要花费很长的时间,这样做也就不合理了。

另一种需要锁粗化的极端的情况是:

for(int i = 0; i < size; i++){
    synchronized(lock){
    }
}

上面代码每次循环都会进行锁的请求、同步与释放,看起来貌似没什么问题,且在 JDK 内部会对这类代码锁的请求做一些优化,但是还不如把加锁代码写在循环体的外面,这样一次锁的请求就可以达到我们的要求,除非有特殊的需要:循环需要花很长时间,但其它线程等不起,要给它们执行的机会。

锁粗化后的代码如下:

synchronized(lock){
    for(int i = 0; i < size; i++){
    }
}

锁消除

锁消除是发生在编译器级别的一种锁优化方式。有时候我们写的代码完全不需要加锁,却执行了加锁操作。

比如,StringBuffer 类的 append 操作:

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

从源码中可以看出,append 方法用了 synchronized 关键词,它是线程安全的。但我们可能仅在线程内部把 StringBuffer 当作局部变量使用:

public class Demo {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int size = 10000;
        for (int i = 0; i < size; i++) {
            createStringBuffer("Hello", "Word");
        }
        long timeCost = System.currentTimeMillis() - start;
        System.out.println("createStringBuffer:" + timeCost + " ms");
    }
    
    public static String createStringBuffer(String str1, String str2) {
        StringBuffer sBuf = new StringBuffer();
        sBuf.append(str1);    // append 方法是同步操作
        sBuf.append(str2);
        return sBuf.toString();
    }
}

代码中 createStringBuffer 方法中的局部对象 sBuf,只在该方法内的作用域有效,不同线程同时调用 createStringBuffer() 方法时,都会创建不同的 sBuf 对象,因此此时的 append 操作若是使用同步操作,就是白白浪费的系统资源。

这时我们可以通过编译器将其优化,将锁消除,前提是 Java 必须运行在 server 模式(server 模式会比 client 模式作更多的优化),同时必须开启逃逸分析:

-server -XX:+DoEscapeAnalysis -XX:+EliminateLocks

其中+DoEscapeAnalysis表示开启逃逸分析,+EliminateLocks表示锁消除。

逃逸分析:比如上面的代码,它要看 sBuf 是否可能逃出它的作用域?如果将 sBuf 作为方法的返回值进行返回,那么它在方法外部可能被当作一个全局对象使用,就有可能发生线程安全问题,这时就可以说 sBuf 这个对象发生逃逸了,因而不应将 append 操作的锁消除,但我们上面的代码没有发生对象逃逸,锁消除就可以带来一定的性能提升。

标签:同步,Java,synchronized,代码,sBuf,粗化,消除,append
From: https://www.cnblogs.com/Higurashi-kagome/p/18278154

相关文章

  • JavaWeb中Session的使用
     Session的工作应用以及工作流程    在浏览器和服务器建立请求访问时,通常会在服务器中开设一个新的JSessionID,用于储存用户的数据,在服务器响应请求后,将JSessionID返回浏览器中,下一次再次进行访问时,浏览器将会直接携带JSessionID进行访问,服务器则直接以此查找Session......
  • 高级java每日一道面试题-2024年7月1日
    题目:请解释Java中的内存泄漏,并说明如何检测和避免内存泄漏。答案:内存泄漏指的是程序中不再使用的对象,由于某些原因没有被垃圾回收器回收,仍然占据着内存空间,导致可用内存逐渐减少,最终可能会导致程序性能下降甚至崩溃。常见的导致内存泄漏的原因包括:长生命周期的对象持......
  • 深入理解Java核心技术模块化局部变量类型推断
    本人详解作者:王文峰,参加过CSDN2020年度博客之星,《Java王大师王天师》公众号:JAVA开发王大师,专注于天道酬勤的Java开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯山峯转载说明:务必注明来源(注明:作者:王文峰哦)深入理解Java......
  • 1974Springboot医院远程诊断管理系统idea开发mysql数据库web结构java编程计算机网页源
    一、源码特点 springboot医院远程诊断管理系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSPjava编程开发语言有帮助系统采用springboot框架(MVC模式开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。springboot医院远程诊断系统......
  • java简单版学生管理系统(无登录,注册界面)
    学生管理系统按照要求定义学生类属性:id,姓名,年龄,家庭住址publicclassstudent{privateStringid;privateStringname;privateintage;privateStringaddress; //以下内容在IDEA中可以使用快捷键ALT+INSEATpublicstudent(){}......
  • 基于Springboot的电子招投标系统。Javaee项目,springboot项目。
    演示视频:基于Springboot的电子招投标系统。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven+Layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界面简......
  • 基于Springboot的书籍学习平台(有报告)。Javaee项目,springboot项目。
    演示视频:基于Springboot的书籍学习平台(有报告)。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven+Layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界......
  • Java身份证实名认证、身份证识别接口让您认证任性的“懒”
    “懒”这个字大多时候是贬义的,但是如果利用好“懒”的特点,就能有不一样的效果。最近几年成功的互联网产品,虽然领域不同,但有一个共同的特点:显著降低了用户获得产品和服务的成本,进而取得成功。不可否认,有不少的产品就是利用了用户越来越“懒”的特点。现在比较火的小视频AP......
  • [JavaScript]“复杂”的 this
    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)https://www.cnblogs.com/cnb-yuchen/p/18277656出自【进步*于辰的博客】参考笔记二,P6.1;笔记三,P72、P73.1。先言我很早就知晓JS的这个知识点——this的重要性,并特意系统学习、理解并有所笔记,但限于平日用得少,对......
  • Java错题归纳(二)
    1、若有如下接口A的定义,下列哪些类下确实现了该接口:CinterfaceA{ voidmethod1(inti); voidmethod2(intj);}A classBimplementsA{voidmethod1(){}voidmethod2(){}}B classBimplementsA{voidmethod1(inti){}voidmethod2(intj){......