2023-11-24 Mr Chang
AE学习
评论(0)
浏览(1109)
2023-11-24 Mr Chang
AE学习
评论(0)
浏览(950)
2023-7-12 Mr Chang
golang
golang 安装第三方包,在golang 1.18版本之后 使用 go get 安装第三方包不会在系统变量 gopath 下面生成对应的 exe文件,可以使用 go install 安装对应的第三方功能才可以生成对应的exe文件。
评论(0)
浏览(1161)
2023-2-6 Mr Chang
golang
var global *int
func f() {
var x int
x = 1
global = &x
}
func g() {
y := new(int)
*y = 1
}
函数f中的x变量虽然是在内部调用的比变量,但是全局变量global调用了内存地址,导致变量逃逸没有在}结束的位置被销毁。此时的x必须存放在堆内存中,相反y在g函数返回的时候不在被调用,y变量可以存放在栈内存当中
评论(0)
浏览(1011)
2022-6-16 Mr Chang
JUC
JIT————Just In Time Compiler 一般翻译为即时编译器。
评论(0)
浏览(1393)
2022-6-16 Mr Chang
JUC
-
Synchronized 锁优化的背景
用锁能够实现数据的安全性,但是会带来性能下降。无锁能够基于线程并行提升程序性能,但是会带来安全性下降。
求平衡???
-
升级流程
Synchronized用的锁是存在Java对象头里的Mark Word中
锁升级功能主要依赖于MarkWord中锁标志位和释放偏向锁标志位
-
锁指向,请牢记
偏向锁:MarkWord存储的是偏向的线程ID;
轻量锁:MarkWord存储的是指向线程栈中Lock Record的指针;
重量锁:MarkWord存储的是指向堆中的monitor对象的指针;
无锁:
初始状态,一个对象被实例化后,如果没有被任何线程竞争锁,那么它就为无锁状态(001)
偏向锁:
单线程竞争
注意:偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程是不会主动释放偏向锁的。
在没有其他线程竞争的时候,一直偏向偏心当前线程,当前线程可以一直执行。偏向于第一个获得它的线程。执行完同步代码块后,线程并不会主动释放偏向锁。
题外话 Java15 逐步废弃偏向锁 默认在虚拟机当中不再开启
重点课程对应 谷粒学院JUC 课时130
轻量级锁:
-
主要作用:有线程来参与锁的竞争,但是获取锁的冲突时间极短,本质就是自旋锁CAS
-
获取:如果关闭偏向锁,则自动升级为轻量级锁
-
如果轻量级锁在自旋达到一定次数仍然不能成功,则升级为重量级锁。
-
自适应自旋的大致原理
线程如果自旋成功了,那下次自旋的最大次数增加,因为JVM认为既然上次成功了,那么这一次也很大概率成功。
反之,如果很少会自旋成功,那么下次会减少自旋的次数甚至不自旋,避免CPU空转。
轻量锁和偏向锁的区别和不同:
-
争夺轻量级锁失败时,自旋尝试抢占锁
-
轻量级锁每次退出同步块都需要释放锁,而偏向锁是在竞争发生时才释放锁
重量级锁 ————指向互斥量(重量级锁)的指针
重量级锁原理
Java中synchronized的重量级锁,是基于进入和退出Monitor对象实现的。在编译时会将同步块的开始位置插入monitor enter 命令,在结束位置插入monitor exit 指令
当线程执行到monitor enter指令时,会尝试获取对象所对应的Monitor所有权,如果获取到了,即获取到了锁,会在Monitor的owner中存放当前线程的id, 这样它将处于锁定状态,除非退出同步块,否则其他线程无法获取到这个Monitor。
JDK1.6之后进行了优化,拥有了无锁->偏向锁->轻量级锁->重量级锁的升级过程,而不是无论什么情况都使用重量级锁。
评论(0)
浏览(1358)
2022-6-16 Mr Chang
JUC
整体结构包括三部分:
-
对象头部 ———— 只有一个对象头的实例对象 只有16字节
对象标记 _mark 字段是mark word
类型指针 _metadata 字段是 klass pointer
对象头(object header)即是由这两个字段组成
这些术语可以参考Hotspot术语表
-
实例数据
-
对齐填充
尾巴参数说明————压缩指针相关说明命令
-
java -XX: +PrintCommandLineFlags -version
-
默认开启压缩指针,-XX: +UseCompressedClassPointers
12 + 4 (对齐填充) = 一个对象16字节
-
手动配置,关闭了压缩指针 -XX: -UseCompressedClassPointers,
8+8 = 一个对象16字节
评论(0)
浏览(1179)
2022-6-13 Mr Chang
JUC
最佳实践:
-
ThreadLocal.withInitial(() -> 初始化值);
-
建议把ThreadLocal 修饰为static。
说明:这个变量是针对一个线程内所有操作共享的,所以设置为静态变量,所有此类实例共享此静态变量,也就是在类第一次呗使用时装载,只分配一块存储空间,所有此类的对象(只要是这个线程内定义的)都可以操控这个变量。
-
用完记得手动remove
总结:
-
ThreadLocal 并不解决线程间共享数据的问题
-
ThreadLocal适用于变量在线程间隔离并且在方法间共享的场景
-
ThreadLocal通过隐式的在不同线程内创建独立实例副本避免了实例线程安全的问题,每个线程持有一个只属于自己的专属Map并维护了ThreadLocal对象与具体实例的映射,该Map由于只被持有它的线程访问,故不存在线程安全以及锁的问题。
-
ThreadLocalMap的Entry对ThreadLocal的引用为弱引用,避免了ThreadLocal对象无法被回收的问题都会通过expungeStateEntry,cleanSomeSlots,replaceStaleEntry这三个方法回收键为null的Entry对象的值以及Entry对象本身从而防止内存泄漏。属于安全加固的方法,群雄逐鹿起纷争,人各一份天下安。
评论(0)
浏览(1134)
2022-6-10 Mr Chang
JUC
threadLocalMap实际上就是一个以threadLocal实例为key,任意对象为value的Entry对象,
void createMap(ThREAD t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
图片形象化解释:
评论(0)
浏览(1108)
2022-6-9 Mr Chang
JUC
AtomicLong 利用 CAS原理不停的在自旋 导致性能消耗,如果涉及高并发,大数据,,,量变引起质变!!!
LongAdder 利用cell数组将热点进行拆分,最后得到统计求和的结果。
result = base + Cell 数组 上述两者全部,才是最后OK。
-
最初无竞争时只更新base;
-
如果更新base失败后,首次新建一个cell[]数组
-
当多个线程竞争同一个Cell比较激烈时,可能就要对Cell[]扩容
Add方法源码解析
-
如果Cells表为空,尝试用CAS更新base字段,成功则推出。
-
如果Cells表为空,CAS更新base字段失败,出现竞争,uncontended为true,调用longAccumulate;
-
如果Cells表非空,当前线程映射的槽为空,uncontended为true,调用longAccumulate;
-
如果Cells表非空,且前线程映射的槽非空,CAS更新Cell的值,成功则返回,否则uncontended设为false,调用longAccumulate。
longAccumulate方法源码解析
评论(0)
浏览(1100)