对象头和synchronized的升级

一、线程的历史

在这里插入图片描述

二、CAS的原理模型

CAS全拼又叫做compareAndSwap,从名字上的意思就知道是比较交换的意思、它是一条CPU并发原语。它包含 3 个参数 CAS(V,E,N),V表示要更新变量的值,E表示预期值,N表示新值。仅当 V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做两个更新,则当前线程则什么都不做。最后,CAS 返回当前V的真实值。

在这里插入图片描述

三、对象头的理解

1、对象在内存中的存储情况

在这里插入图片描述

注释:Markword 对象头占用8字节 、class pointer 类型指针占用4个字节 、instance data 实例数据、padding 对齐(主要作用是补齐字节数,达到被8整除的状态)。

  • 小知识
C:\>java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=131697344 -XX:MaxHeapSize=2107157504 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.8.0_291"
Java(TM) SE Runtime Environment (build 1.8.0_291-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)


​ 解释:在这个指令中,可以打印出的参数的类型

​ -XX:InitialHeapSize=131697344表示的是起始的堆大小,

​ -XX:MaxHeapSize=2107157504表示的是最大的堆的大小

​ -XX:+PrintCommandLineFlags表示的是输入的堆的大小

​ -XX:+UseCompressedClassPointers表示的是压缩指针,占用4个字节

​ -XX:+UseCompressedOops表示的是普通对象指针,默认是压缩的4个字节

​ -XX:+UseCompressedOops

Java的指针的长度是64位,8个字节的,在默认开启了指针压缩后,会压缩成为4个字节

2、实际操作

2.1引入maven依赖

<!--    引入jol工具的依赖-->
    <dependency>
      <groupId>org.openjdk.jol</groupId>
      <artifactId>jol-core</artifactId>
      <version>0.11</version>
    </dependency>
  </dependencies>

2.2写入测试代码

public class T01 {
    public static void main(String[] args) {

        Object o = new Object();

        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

解释:

2.3执行方法后的结果

Connected to the target VM, address: '127.0.0.1:61099', transport: 'socket'
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

img

在图片中可以看到对象头是占用了8个字节,压缩指针占用4个字节,在后面由于不能被8整除,使用字节进行补齐。

四、锁状态的描述

img

解释:图中的unused表示没有使用,位数对应的值在该状态下使用的位数。

1、无锁状态:25位没有用;31位装的identity Hashcode,但是只有在被调用的时候,才填充,没有调用的时候是空的;1位没有使用的;4位分代年龄;1位偏向锁位;2位锁标志位。

2、偏向锁:54位存下当前线程的ID;2位存批量撤销Epoch;1位没有使用;4位分代年龄;1位偏向锁位;2位锁标志位。

3、自旋锁:62位指向线程中的Lock Record的指针。Lock Record与锁重入有关,synchronize默认是可重入的。自旋锁在竞争锁的时候,会在自己的内存的线程栈中创建一个Lock Record对象,抢到锁对象的资源时,锁对象头存的就是这个线程的Lock Record对象的指针,所以在重入的时候,会再创建一个Lock Record对象,利用Lock Record来记录到底琐了多少次。解锁的时候,就将一个Lock Record移除,移除的方式是FILO,也就是先进后出的原则。

4、重量级琐:重量级琐是在C++代码层面进行的,会生成一个ObjectMonitor对象,这个对象中记录了一系列的队列,

5、 分代年龄:JVM有10种垃圾回收器,前面7种都涉及分代年龄,采用分代算法。当我们创建一个对象的时候,把它放在年轻代中,每经过一次垃圾回收后年龄就+1,也就是垃圾回收无法回收掉这个对象,它的年龄就会不断的增长,到达15,因为4个字节最大为15,就转到老龄代,年轻代的回收就不再对它进行回收。

五、synchronized的升级过程

img

    注意:

    (1) 琐升级路线:new -> 偏向锁 -> 轻量级琐(自旋锁、自适应自旋锁) -> 重量级琐

    (2) 如果偏向锁没有启动,那么new出来的对象是普通对象;如果偏向锁已经启动,那么new出来的对象就是匿名偏向对象。

    (3) 偏向锁什么情况下转为轻量级琐呢?只要有2个线程竞争同一个琐资源,所有线程都升级为轻量级琐,也就是都会自旋抢占琐资源。

    (4) 自旋锁在竞争资源的时候,也是CAS操作,用CAS的方式修改琐对象的mackword。

    (5) 自旋锁升级为重量级琐需要符合什么条件呢?jdk1.6以前,某个线程自旋次数上限达到默认的10次,会升级为重量级锁,因为一直自旋消耗CPU资源;自旋线程数量达到了默认是系统的CPU核数的1/2的时候,全部升级为重量级琐进入等待队列。jdk1.6之后,jdk提供了自适应自旋,jdk根据每个线程的运行情况来判断是否需要升级。

六、总结

主要通过学习,了解对象头的相关知识和synchronized的升级过程。如有不对的地方敬请指导交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的synchronized升级是为了提高多线程并发执行的性能和效率。它通过在锁的使用过程中进行优化和升级来实现。 在Java中,synchronized锁的升级主要涉及三个层面:Java层面、字节码层面和JVM层面(对象)。 在Java层面上,synchronized锁的升级包括以下几种状态: 1. 无锁状态:多个线程可以同时进入临界区,没有互斥的限制; 2. 偏向锁状态:当只有一个线程访问临界区时,偏向锁可以减少锁的竞争; 3. 轻量级锁状态:多个线程竞争同一个锁时,锁会升级为轻量级锁,通过CAS操作来实现快速的加锁和解锁; 4. 重量级锁状态:多个线程竞争同一个锁时,锁会升级为重量级锁,使用操作系统的互斥量来实现线程的阻塞和唤醒[1]。 在字节码层面上,synchronized同步代码块的锁升级实际上是通过字节码指令来实现的。当进入同步代码块时,会通过monitorenter指令获取锁,在退出同步代码块时,会通过monitorexit指令释放锁。这些指令可以保证临界区的原子性和互斥性,从而实现线程的同步。 在JVM层面上,synchronized锁的升级是通过对象中的标记位来实现的。对象中的标记位包括了锁标志位、线程ID和指向锁记录的指针。通过这些标记位,JVM可以判断锁的状态和竞争情况,从而进行锁的升级和降级。 总结来说,Java中的synchronized升级是为了提高多线程并发执行的性能和效率。它通过在不同层面上对锁进行优化和升级来实现线程的同步和互斥,从而保证临界区的原子性和正确性。这些优化和升级包括了无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值