对象在内存中的结构是什么样的?
对象在堆内存中主要分为四个部分:
Markword:记录锁的状态和对象的生命信息,例如是否GC,经历过几次YoungGC还存活;什么样的对象会进入老年代?对象太大或者被GC15次还存活
KlassPoint:指向class文件的指针
instance date:对象实例化数据
padding:对齐字节,规定对象内存的大小必须能被8字节整除,如不能进行填充
利用第三方工具包 Java Object Layout ClassLayout.parseInstance(o).toPrintable()
对象头占用12个字节
锁的升级验证
Sync锁升级之后,jdk1.8版本默认设置4秒钟之后开发偏向锁,若是在4秒钟之内加锁直接升级为轻量锁
为什么要进行锁升级,而不能直接加锁?
操作系统为了安全分成了内核态和用户态,用户态加锁需要向内核态进行申请,然后内核态再还给用户态,这个过程相当耗时,所以jvm就可以完成的锁操作拉取出来提升效率,就有了锁优化。
为什么有偏向锁?
这是一个概率问题,日常sync的过程大部分情况下都只有一个线程持有锁,基本上没有锁竞争,也就没有必要将锁升级为轻量锁。第一个线程拿到锁以后,下次进来就没有必要再进行锁验证。如果有第二个线程来竞争锁,再将偏向锁撤销,升级为轻量锁。
偏向锁为什么4秒钟之后再开启?
因为线程启动若是有很多线程来抢锁,如果开启偏向锁,还需要将其撤销,再升级为轻量锁,反而会效率下降,等4秒钟来确定没有多线程竞争再开启偏向锁,我什么是4秒是个统计时间。可以通过参数-XX:UseBiasedLocking=false来禁用偏向锁,jdk15默认禁用
锁的升级过程
对象从创建后进入内存,从无锁状态→偏向锁(如果开启)→轻量锁→重量级锁,轻量级锁就是资源由一个线程持有变为多个线程竞争,如果竞争不激烈,线程自旋等待获取资源的条件,自旋次数不多就可以拿到资源,也就没必要进行更重的锁操作。
轻量级锁为什么要升级为重量级锁
轻量锁carry不住的情况下会升级为重量级:1、线程太多,CPU在巨多的线程中来回切换消耗大量的资源,这种情况下自然就升级为重量级锁,让线程排队等待;2、CAS自旋次数超过10次依然没有获得到锁,也会升级为重量级锁,以避免浪费CPU资源
sync到底重在哪里
JVM偷懒把任何跟线程有关的操作全部交给操作系统去做,例如调度锁的同步直接交给操作系统去执行,而在操作系统中要执行先要入队,另外操作系统启动一个线程时需要消耗很多资源,消耗资源比较重,重就重在这里
Synchronized的底层实现原理
反编译代码后,会发现在代码块中,有一对monitor操作,enter和exit,这就是加锁和解锁的指令。sync与lock的区别,sync是jvm层的锁,jvm会自动帮助释放锁,而lock需要手动释放。