美团7连问(jvm)
作者:互联网
感谢大佬的录屏,延迟看一下JVM的视频课程,记一下笔记:
开篇这玩意儿我暂时也看不懂,先放在这里:
接下来给了一段创建对象的代码,以及它的java汇编码
字节码:
0.new ->申请内存。堆里有了一个新的内存。(半初始化。成员变量设置默认值)
3 dup 因为invokespecial会消耗一份,所以必须先复制一份
4 invokespecial T initlize 初始化,调用他的构造方法
7 astore_1 把t与T建立关联
8 return
那么上图的第一个问题就解决了。看第二个问题。DCL与violatile
设计模式:单例:new Class时候,只要求内存中只能new出一个对象。
里面调getInstance永远只有一个对象
或者:
上来先判断,if instance为空再new出来。(多线程访问的时候并不安全,多线程可能会new多个instance)
所以如果有多线程访问时:在方法加synchronize。永远只有一个线程访问:但是整个方法全上锁了,没考虑业务内容是否也需要被锁
如果为空,再上锁。但卡的位置不对,第一个线程还没来得及new,第二个线程又来了,还是空,那第二个线程也new。所以不合适
所以!!DCL:
先上锁,再判空。检查两遍double check lock DCL 单例写法
单例前面是否要加 violatile:
1.保持线程可见性
2.禁止指令重排序 (本来CPU多条流水线执行)
DCL单例情况下重排序:
发生指令重排序后,使m初始化后,m不为空。此时thread2直接拿到m=0了。
所以必须要加volatile禁止指令重排序!对m这个对象的内存区域加volatile,对这块区域的读写都要加memory barrier
3.对象在内存中的存储布局
(markword标记字 8字节/class pointer类型指针 4字节)
统称为对象头。上图订正。
总长度要能被8整除,提高效率,所以后面会有个对齐 (计算机总线,cpu总线,寄存器,最好都是8个字节往里扔)
对象上锁后的变化(所以能看出markword里面有锁信息)
以下锁状态全部记录在markword里面
偏向锁:biased lock: JVM认为大多数情况下这把锁也就一个线程在用,当第一个线程过来的时候,没有必要上锁,就把名片往上面一贴。奥利给!那么这个坑就是你的,上面贴着你的名片,再来点时候也不需要竞争。
偏向锁 没有锁竞争的过程,上锁很快,效率很高
当特朗普看到上面有奥利给的名字,那么就有锁竞争了。先把奥利给名片扯下来,通过CAS的方式,往上贴名片,谁贴上去这个坑就是谁的。
CAS:(无锁状态)
比如说线程要给内存中的0进行+1操作,如果不加锁的话,就先将这个数字读出来,再在内存中做计算,再把这个1往回写。
写的时候检查内存中的0是否还是0,如果还是0,就直接写入1。
但如果内存中不是0,是1了,那就读1,回去重新计算+1,再往回写2
这种方法不用加锁,但存在AB A问题。怎么解决?加入版本号
CAS设定lock record。奥利给在里面憋着干活,特朗普在外面急着转圈,自旋,读标签。
自旋锁:当旋转次数超过cpu核数的1/2,会升级到最后的重量级锁 (java5.0前)算法
后面升级到自适应自旋,就是旋转次数不进行设置,由JVM自适应设置,看是否需要升级重量级锁,向操作系统老大申请资源。
轻量级锁 lock-free:
重量级锁:要向操作系统申请锁资源。JVM对应线程放进这把锁的等待队列里,什么时候轮到你,什么时候执行。(旋转的人太多,把你冷冻了。让这些抢不到锁的线程不会消耗cpu)
以上所有的锁都是互斥锁
截止obj.mp4视频 65:14
5.6.7今天先不看了待续
标签:DCL,jvm,美团,JVM,线程,内存,连问,new,上锁 来源: https://www.cnblogs.com/tiancai/p/13151633.html