美文网首页
synchronized底层如何实现

synchronized底层如何实现

作者: 黑小鹰 | 来源:发表于2018-12-08 14:50 被阅读2次

    synchronized底层如何实现?什么是锁的升级、降级?

    synchronized代码块是由一对儿monitorenter/monitorexit指令实现的, Monitor对象是同步的基本实现单元。

    在Java 6之前, Monitor的实现完全是依靠操作系统内部的互斥锁,因为需要进行用户态到内核态的切换,所以同步操作是一个无差别的重量级操作。

    现代的(Oracle) JDK6中, JVM对此进行了大刀阔斧地改进,提供了三种不同的Monitor实现,也就是常说的三种不同的锁:偏斜锁(Biased Locking)、轻量级锁和重量级锁,大大改进了其性能。

    锁的升级、降级,就是JVM优化synchronized运行的机制,当JVM检测到不同的竞争状况时,会自动切换到适合的锁实现,这种切换就是锁的升级、降级。

    偏向锁

    引入偏向锁的目的:在没有多线程竞争的情况下,尽量减少不必要的轻量级锁执行路径,轻量级锁的获取及释放依赖多次CAS原子指令,而偏向锁只依赖一次CAS原子指令置换ThreadID,不过一旦出现多个线程竞争时必须撤销偏向锁,所以撤销偏向锁消耗的性能必须小于之前节省下来的CAS原子操作的性能消耗,不然就得不偿失了。JDK 1.6中默认开启偏向锁,可以通过-XX:-UseBiasedLocking来禁用偏向锁。

    偏向锁的撤销

    只有当其它线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,偏向锁的撤销由BiasedLocking::revoke_at_safepoint方法实现:

    轻量级锁

    引入轻量级锁的目的:在多线程交替执行同步块的情况下,尽量避免重量级锁引起的性能消耗,但是如果多个线程在同一时刻进入临界区,会导致轻量级锁膨胀升级重量级锁,所以轻量级锁的出现并非是要替代重量级锁。

    重量级锁

    重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。


    java对象头实现

    HotSpot虚拟机中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充。
    对象头
    对象头包括两部分:Mark Word 和 类型指针。

    Mark Word
    Mark Word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,占用内存大小与虚拟机位长一致。

    类型指针
    类型指针指向对象的类元数据,虚拟机通过这个指针确定该对象是哪个类的实例。

    hash: 保存对象的哈希码
    age: 保存对象的分代年龄
    biased_lock: 偏向锁标识位
    lock: 锁状态标识位
    JavaThread:* 保存持有偏向锁的线程ID
    epoch: 保存偏向时间戳


    image.png

    参考文献:
    JVM源码分析之synchronized实现
    JVM源码分析之java对象头实现

    相关文章

      网友评论

          本文标题:synchronized底层如何实现

          本文链接:https://www.haomeiwen.com/subject/pkttcqtx.html