zoukankan      html  css  js  c++  java
  • JAVA虚拟机JVM-6.锁优化

    JAVA的锁优化

    锁优化包含:自适应性自旋、锁消除、锁膨胀、轻量级锁、偏向锁。以下为锁的升级过程:

    自旋锁与自适应自旋

    JDK1.6之前自旋默认是关闭的,之后是默认开启的。自旋等待避免了线程状态转换带来的性能开销,但是需要占用处理器的时间,如果占用时间很短,效果很好,如果占用时间很长,会白白消耗处理器资源。默认自旋的次数是10次,超过这个次数会挂起线程。

    自适应自旋是在自旋的时间不在固定,而是由上一次在同一个锁上的自旋时间及锁的拥有者的状态来决定的。

    轻量级锁

    轻量级锁设计初衷是为了在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

    轻量级锁以及偏向锁依赖于JVM的对象内存分布,对象头包含锁的相关信息。具体如下:

    如果出现两条以上的线程竞争同一个锁的情况,那轻量级锁就不在有效,必须要膨胀为重量级锁。

     偏向锁

    偏向锁会偏向第一个获得它的线程,如果在接下来的执行过程中,该锁一直没有被其他线程获取,则持有偏向锁的线程将永远不在需要进行同步。

    一旦出现另一个线程去尝试获取这个锁的情况,偏向模式就立即结束,根据锁对象目前处于是否被锁定决定是否撤销偏向,撤销后锁升级为轻量级锁或者恢复到为锁定状态。

    锁消除

    锁消除是指在虚拟机即时编译器在运行时,对一些代码要求同步,但是对被检测到不可能存在共享数据竞争的锁进行消除。(我们写了锁,但是虚拟机可以给我们优化掉)

     编译后代码:

     

    现在大家还认为这段代码没有涉及同步吗?每个StringBuffer.append()方法中都有一个同步块,锁就是sb对象。虚拟机观察变量sb,很快就会发现它的动态作用域被限制在concatString()方法内部。也就是sb的所有引用永远不会“逃逸”到concatString()方法之外,其他线程无法访问到它,所以这里虽然有锁,但是可以被安全地削除掉,在即时编译之后,这段代码就会忽略掉所有的同步而直接执行了。

    锁粗化 

    原则上我们写代码的时候会减少锁以及同步块的作用范围。只在共享数据的实际作用域进行同步。但是如果一系列的连续操作都是对同一个对象反复加锁、解锁,那么我们就要进行锁的粗化优化。

    比如JVM自己优化的String字符串的相加,javac会转换程一个StringBuffer对象进行多次append()操作,而不是多个StringBuffer对象,进行多次append,这样只需要加一次锁就可以了。

    减小锁的粒度

    除了锁内部优化和编译器优化之外,我们还可以通过代码层来实现锁优化,减小锁粒度就是一种惯用的方法。

    当我们的锁对象是一个数组或队列时,集中竞争一个对象的话会非常激烈,锁也会升级为重量级锁。我们可以考虑将一个数组和队列对象拆成多个小对象,来降低锁竞争,提升并行度。

    最经典的减小锁粒度的案例就是 JDK1.8 之前实现的 ConcurrentHashMap 版本。我们知道,HashTable 是基于一个数组 + 链表实现的,所以在并发读写操作集合时,存在激烈的锁资源竞争,也因此性能会存在瓶颈。而 ConcurrentHashMap 就很很巧妙地使用了分段锁 Segment 来降低锁资源竞争,如下图所示:

  • 相关阅读:
    hdu1506(dp)
    windows下安装JMeter
    phpstudy 80端口被占用,修改端口
    久违的phpstorm
    软件项目版本号的命名规则及格式
    phpstudy 局域网访问
    java+eclipse+selenium环境搭建
    软件测试方法汇总
    功能测试大全
    如何有效地描述软件缺陷(Defect)?
  • 原文地址:https://www.cnblogs.com/wangb0402/p/12653956.html
Copyright © 2011-2022 走看看