多线程 术语(关键字背诵(理解),直怼面试官)
死锁
2条线程互相持有各自的锁的时候,又要获取对方已持有的锁时产生 抱死
解决办法:
1.始终使用相同的加锁顺序(1.hashcode 的大小值,2.其他和锁相关的不变量,比如ID号大小)
2.使用一个总锁,只对唯一的总锁竞争,然后在互斥区内再获取另外的2个锁
3.排查死锁问题,需要对整个程序中所有的锁有全局观
检测算法有银行家算法
GUI框架为什么往往是单线程的?
因为很容易引发顺序锁产生的死锁,并且如果设计为适用于多线程,那么使用框架的程序员必须对整个框架的锁和可能存在的死锁问题有非常深入的全局观才能运用的好(学习成本高),一旦发生死锁问题将难以排查;所以为了保持开箱即用和简单的原则,大多数GUI框架都是单线程的(AWT项目从中吸取经验)
活锁
由于过度错误恢复策略造成
解决办法:
引入随机量
如2个信号发射装置,同时发射信号,同时检测到干扰,并等待1秒重试,结果又发生干扰,又重试。。。如此循环。 解决:只需要再等待时间上加入一个随机间隔
开放调用
指所设计的方法函数,内部不需要持有任何加锁;这可以简化复杂的多重锁情况下的分析难度。
饥饿
指线程无法获取需要的资源,如低线程优先级的线程进入互斥区后,因为始终得不到CPU时间片,造成其他线程想要获取锁时一直阻塞
线程封闭
一个对象只能所属的线程拥有和进行读写;如ThreadLocal 类,本质是访问当前所属Thread对象中的容器字段。
栈封闭
线程封闭的的一个特里,在栈中的对象,不应该在离开栈后,还可以被访问
CAS
比较并设置
由处理器提供的指令,可以保证原子性的完成 读改写 ,当作函数来看的话有3个参数1个返回 oldValue CASfunction(memAddr , value, newValue);
当指定内存中的值等于value时,将newValue写入,并返回旧值;若当指定内存中的值不等于value时,不写入newValue,直接将旧值返回
可以用于 i++ 这种情况的操作,保证了可靠性
CAS操作常常在在竞争程度低时使用,效率比加锁高大约1倍
voalite
只能解决可见性,当值被修改后,会通知其他线程,读取值的时候不会读缓存,也不会进行指令重排
单线程时可以依赖旧值做 读改写,否则只可以直接读或写,不可以依赖旧值(除非加锁或用CAS)
volaite变量看似像是直接操作主存中的数据,但实际也是要把数据 读取,载入,到工作内容 然后使用,赋值,存储,写入到主存, 每次读写时不保存缓存中的
逸出
将私有变量的引用发布到外部,外部可以意外的修改其内容,而如果外部是在多线程环境中使用的话,可能会产生线程安全问题
vm多线程内存模型
线程->工作内存->|S/L操作|->|主存|
线程->工作内存->| |->| |
配合8个主要指令 :锁定 读取 载入 使用 赋值 存储 写入 解锁,在主存和工作内存和执行引擎之间操作数据
5种线程状态
2种线程调度
3种线程模型
内核线程(KLT->LWP),用户态线程(UT),内核+用户混合线程(N个KLT : M个UT)
内存屏障
在多处理器、内核环境中,为了保证同一数据的可见性,X86 用 LOCK 前缀,如 LOCK addl $0,eax ,执行一条空操作,让Cache中的数据写入内存,并通知系统中其他处理器、内核于此相关的Cache失效。volatile关键字有使用此特性。
VM中8个内存交互操作
枷锁,解锁,读取,载入,使用 (执行引擎) 赋值,存储,写入
锁消除
编译时,如果检测到是在单线程下,去除掉一些加锁操作,优化性能
对象头
32位vm有 32位对象头, 分2部分, 1.对象类型指针,如果是数组还有数组长度 2.Mark World
Mark World 包含:25bit hashCode ,4bit 对象新生代/老年代年龄,2bit 加锁表值 , 1bit 固定0值
强软弱虚引用
软,内存不够时,被回收
弱,下次gc时被回收
虚,用作被回收时的通知消息
GC算法
标记-清除:标记要被回收的,然后清除
标记-复制:标记要被保留的,然后有序的复制到存储区域中,覆盖需要被清除的
复制:1个大Eden,2个小survival,将需要保留的从Eden和一个survival复制到另一个survival,将之前的survival和Eden清除
混合:老年代用标记-清除 或 标记-复制,新生代用复制
新生代,老年代
对象是否属于老年代,根据经历的GC次数,并存活
类加载
当遇到get/set/invoke static 和 new vm指令时,发生类加载
加载,验证,准备,解析,初始化,使用,卸载
| 链接 |
加载文件,分配Class对象
验证文件头魔数等
分配方法区内存空间,并赋值0
解析类,方法,接口,字段
调用类的 1.成员字段初始化 2.自定义static静态块(<cinit>) 3.构造函数(<init>)