一、Volatile
- 可见性: 使用volatile修饰的对象,对其他线程可见。当线程A修改对象t后,会将t写回主内存,因为缓存一致性原则,当线程B修改t时,会从主内存中读取最新的t。
- 禁止指令重排序。实现过程:
a. java层面添加volatile关键词。
b. 编译为java字节码后,对象前会添加修饰符ACC_VOLATILE。
c. 在jvm层面,会在指令前后增加内存屏障,禁止指令重排。根据JSR规范,内存屏障分类: LoadLoad,StoreStore,LoadStore,StoreLoad。
d. 在汇编层面是通过Lock指令锁总线来实现的。
二、强软弱虚引用
- 强引用: 正常的引用,没有任何引用指向的对象会被垃圾回收器回收。
- 软引用: 当内存不够时,软引用会被回收,经常用作缓存。
- 弱引用: 只要只有弱引用指向的对象,垃圾回收时就会被回收,应用场景: ThreadLocal。
- 虚引用: 堆外内存管理,比如 zerocopy; 直接内存管理,比如nio。
三、ThreadLocal
1. 概念
ThreadLocal 叫做本地线程变量,意思是说,ThreadLocal 中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的。
2. 源码实现
在Thread类中,有一个ThreadLocalMap的成员变量 threadLocals,ThreadLocal对象 tl 执行set方法时,会从当前线程中获取threadLocals变量,然后以当前ThreadLocal为key,保存进ThreadLocalMap中的Entry数组中,而Entry继承了WeakReference<ThreadLocal<?>>(弱引用), 因此指向ThreadLocal对象的有两条引用,一条tl强引用,一条ThreadLocalMap中key指向的弱引用,这样当tl为null时,垃圾回收时可以直接回收ThreadLocal。
3. ThreadLocal的内存泄漏
当强引用tl为null时,ThreadLocal会被回收,导致ThreadLocalMap中key值为null,value值再也无法被获取到,这部分空间无法被回收。
解决方法: 当确认ThreadLocal不再被使用时,执行remove()方法,将ThreadLocalMap中的key和value清除,释放空间。