image.png

    • 偏向锁
      • 偏向第一个线程的锁
      • 不需要操作系统起线程锁, 只要标记好线程id就可以进去了 把markword改为线程id
      • jkd1.8 默认开启偏向锁的, 一般4s后开启(jvm启动的时候会开启一些线程,会产生竞争 ,导致偏向锁撤销,反而影响性能)
      • 如果有线程竞争
        • 撤销偏向锁,升级轻量级锁
        • 线程在自己的线程栈生成lockRecord,用CAS 操作将markword设置指向自己这个线程的lockRecord的指针,设置成功者货到锁
      • 如果竞争加剧
        • 竞争加剧 有线程超过10次自旋,或者自旋线程数超过cpu核数的一半,1.6之后,加入自适应自旋jvm自己控制
    • 轻量级锁
      • CAS 等不需要操作系统来操作的锁
    • 重量级锁
      • 将加锁交给操作系统来做,因为操作系统起一个线程 非常消耗资源,所以称为重量级
    • 锁升级的步骤
      • new 一个对象
        • 如果偏向锁没有启动,则就是一个普通对象,先是上轻量级锁, 在升级为重量级锁
        • 如果偏向锁启动了,这个对象的对象头已经是101了,默认就是偏向状态, 称为匿名偏向
        • 此时上的锁就是偏向锁, 如果有竞争就会升级为轻量级锁,在升级为重量级锁
    • image.png
    • 对象布局
      • 对象在内存分为:
        • 对象头(object header):包括了关于堆对象的布局、类型、GC状态、同步状态和标识哈希码的基本信息。Java对象和vm内部对象都有一个共同的对象头
          • mark word
          • 在64位JVM中是这么存的
          • image.png
          • class pointer :即类型指针,是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
          • 锁标志位(lock):区分锁状态,11时表示对象待GC回收状态, 只有最后2位锁标识(11)有效。
          • biased_lock:是否偏向锁,由于无锁和偏向锁的锁标识都是 01,没办法区分,这里引入一位的偏向锁标识位。
          • 分代年龄(age):表示对象被GC的次数,当该次数到达阈值的时候,对象就会转移到老年代。
          • 对象的hashcode(hash):运行期间调用System.identityHashCode()来计算,延迟计算,并把结果赋值到这里。当对象加锁后,计算的结果31位不够表示,在偏向锁,轻量锁,重量锁,hashcode会被转移到Monitor中。
          • 偏向锁的线程ID(JavaThread):偏向模式的时候,当某个线程持有对象的时候,对象这里就会被置为该线程的ID。 在后面的操作中,就无需再进行尝试获取锁的动作。
          • epoch:偏向锁在CAS锁操作过程中,偏向性标识,表示对象更偏向哪个锁。
          • ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针。当锁获取是无竞争的时,JVM使用原子操作而不是OS互斥。这种技术称为轻量级锁定。在轻量级锁定的情况下,JVM通过CAS操作在对象的标题字中设置指向锁记录的指针。
          • ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针。如果两个不同的线程同时在同一个对象上竞争,则必须将轻量级锁定升级到Monitor以管理等待的线程。在重量级锁定的情况下,JVM在对象的ptr_to_heavyweight_monitor设置指向Monitor的指针
        • 实例数据(Instance Data):主要是存放类的数据信息,父类的信息,对象字段属性信息。
        • 对齐填充(Padding):为了字节对齐,填充的数据,不是必须的.