zoukankan      html  css  js  c++  java
  • 【Java】【JVM】Sychronized底层加锁原理详解

    • 我们首先先看看JMM模型,话不多说,上图:

    • JMM对应的8大原子操作:
    read(读取):从主内存读取数据
    load(载入):将主内存读取到的数据写入工作内存
    use(使用):从工作内存读取数据来计算
    assign(赋值):将计算好的值重新赋值到工作内存中
    store(存储):将工作内存数据写入主内存
    write(写入):将store过去的变量赋值给主内存中的变量
    lock(锁定):将主内存变量加锁,标示为线程独占状态
    unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量

    • Sychronized底层对应的JMM模型8大原子操作【lock】和【unlock】
    • 此时即可同时保持
      • 【原子性】:代码成块
      • 【有序性】
      • 【可见性】

    感兴趣的同学,可以对代码编译后,看下反编译后的指令,此处我们分析一下:

    • 原理:
      • JVM内置锁通过synchronized使用,通过内部对象Monitor(监视器锁)实现,基于进入与退出Monitor对象实现方法与代码块同步,监视器锁的实现依赖底层操作系统的Mutex Lock(互斥锁)实现,它是一个重量级锁,性能较低。

    • 如果此时存在一个object2,那么当object1对应线程结束后,只唤醒object1对应阻塞队列中的线程:

    • Monitor加锁原理:每个同步对象都有一个自己的Monitor(锁监视器)
      • JVM加锁过程:JVM内置锁,有没有办法能够手动控制加锁与解锁?

    • JDK1.6版本之后对synchronized的实现进行了各种优化,如适应性自旋锁、轻量级锁和偏向锁,并默认开启偏向锁
    开启偏向锁:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
    
    关闭偏向锁:-XX:-UseBiasedLocking

    上面详细说了一下重量级锁,如果是轻量级锁,那么就没有对应的【Monitor】监视类,那么轻量级锁是如何进行区分的呢?

    • 来!这里看一下对象结构,不墨迹,撸图:

    •  这里张贴一段jdk源代码(有些深度)
    oop.hpp:

    class
    oopDesc { friend class VMStructs; private: volatile markOop _mark; union _metadata { Klass* _klass; narrowKlass _compressed_klass; } _metadata;
    markOop.hpp:
    // 32 bits: // -------- // hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object) #正常的对象状态 // JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object) #偏向锁的对象状态 // size:32 ------------------------------------------>| (CMS free block) // PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object) // // 64 bits: // -------- // unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object) // JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object) // PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object) // size:64 ----------------------------------------------------->| (CMS free block)
    • 这里Mark Word在32位JVM中存储内容为例:

    • 问题又来了,那么JVM内置锁升级优化过程是如何的呢?

     

    • 偏向锁高效原因:

    只需要修改【Object Mark Word】中的【hashcode】标志位为当前线程对应的【Thread ID】;

    而如果直接切换到重量级锁,则是一个用户态到内核态的切换。

    • 偏向锁可以被撤销么?

    当然可以被撤销,不过要等到当前拥有锁的线程达到安全点,即执行完同步块,才可以撤销。

  • 相关阅读:
    【剑指Offer】21、栈的压入、弹出序列
    【剑指Offer】20、包含min函数的栈
    【剑指Offer】19、顺时针打印矩阵
    【Shell编程】Shell基本语法
    【Shell编程】Shell程序设计
    linux 大中括号变量解读
    Python 二进制,十进制,十六进制转换
    Python3.x和Python2.x的区别
    python通过SSH登陆linux并操作
    PEP8特性
  • 原文地址:https://www.cnblogs.com/boluopabo/p/12907916.html
Copyright © 2011-2022 走看看