• Java并发——Synchronized


     
     
     

    Synchronized是jvm提供支持的锁,和Lock有很多区别。

    针对Synchronized,jvm支持不同层次的实现。按竞争烈度来说,Synchronized会有偏向锁,轻量级锁,重量级锁等3种类型。

    针对对象而言,在对象头上的Mark word上会存储锁信息(包括:偏向线程ID、偏向时间戳,是否偏向锁等),对象的hashcode,分代信息等。

    针对线程来说,其会维护一个monitor集合,每一个对象都会与获取该对象锁的线程的monitor建立关联。

    • 偏向锁

    当线程第一次进入同步块时,如果对象头尚未记录偏向锁信息,此时会在对象头的Mark word中登记偏向锁。但是,在线程离开同步块时,这个偏向锁不会主动释放,仍然存留在对象头中。后续线程再次进入同步块时,仅需要从对象头的Mark Word中提取出来判断是否当前线程的偏向锁即可。如果是当前线程,则继续执行,不做任何操作。如果不是当前线程,则判断对象头中记录的线程是否存活,是否还在使用此对象的锁。如果记录的线程死亡或者不再使用,jvm会将该对象恢复至无锁状态。如果还在使用,则升级成轻量级锁。

    偏向锁解决的问题是,基本无竞争场景下,降低锁的获取释放成本。

    • 轻量级锁

    当偏向锁出现线程竞争时,锁会升级成轻量级锁。在竞争轻量级锁时,未获取到锁的线程会自旋若干次数。在自旋期间获取到锁,则获取锁成功,否则自旋超时,锁会继续升级为重量级锁。当然,如果自旋期间,有新的线程参与竞争,也会直接升级为重量级锁。

    轻量级锁解决的问题是,在非常低烈度的竞争场景,锁的占用时间也非常短暂时,线程通过一定的自旋次数可以获取到锁。即自旋的成本<<线程挂起&唤醒的成本时,通过线程的自旋可以降低成本。

    • 重量级锁

    在竞争激烈的场合,线程无法通过少量的自旋来获取到锁,直接挂起排队等待效率更高。

    故而,针对Synchronized而言,锁会分为4个级别,无锁,偏向锁,轻量级锁,重量级锁。按竞争程度逐步升级。不同级别的锁实现的方式互有差异,偏向锁仅在对象头的Mark Word上记录,仅一次cas操作即可。轻量级锁依赖线程栈,因为存在竞争的缘故,需要多次cas自旋操作才可能获取到锁。重量级锁则直接挂起线程,不会有自旋等动作的产生。

    Synchronized与Lock相比,在竞争不激烈场景下,锁膨胀的这个过程,Lock也可以通过代码进行模拟。但是Synchronized不支持超时,不支持公平非公平,不支持乐观锁等条件,适用面相比会稍窄一些。

    Synchronized支持主动唤醒,依赖Object的wait,notify,notifyAll。线程在执行sleep时,不会主动释放锁信息,但是在执行wait时,会释放获取到的锁信息。故在执行wait,notify,notifyAll时,需要通过Synchronized的同步代码块包装后再执行。

    • 锁消除

    jvm中有一个锁消除的参数配置,在编译期间,如果发现加锁的代码不会有并发可能性,jvm会主动做锁消除,避免无意义的锁。

    -XX:+DoEscapeAnalysis -XX:+EliminateLocks

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

    参考资料:

    http://www.itsoku.com/article/86#menu_3

  • 相关阅读:
    记第一次重装系统
    数值运算_第1周
    更新驱动时显示失败,错误代码56
    Tomcat安装教程及常见错误解决方法
    中国学术界之特点
    Mac 安装qtbingdings出现error 解决方式
    关于xtea加密解密算法
    关于消息认证码
    2、关于协议数据包的设计
    关于协议标识符的实现方法
  • 原文地址:https://www.cnblogs.com/asfeixue/p/13954043.html
Copyright © 2020-2023  润新知