- 强引用:使用 new 方法创造出来的对象,默认都是强引用。GC的时候,垃圾回收器将永远不会回收被引用的对象,就算内存不够,抛出OutOfMemoryError 也不会回收对象,死了也不回收。
- 软引用:使用 SoftReference 修饰的对象被称为软引用。软引用指向的对象,如果内存够不回收,内存不够则回收。常用于内存敏感的应用,比如高速缓存。;
- 弱引用:使用 WeakReference 修饰的对象被称为弱引用。弱引用指向的对象,无论内存够不够,GC的时候都回收,也可以用在高速缓存上。
- 虚引用:使用 PhantomReference 修饰的对象被称为虚引用,虚引用是最弱的引用。虚引用指向的对象,和没有任何引用⼀样,在任何时候都可能被垃圾回收;虚引用中唯一的作用就是用队列接收对象即将死亡的通知;基本上不会使用!
- ThreadLocal 类主要解决的就是让每个线程绑定⾃⼰的值,可以将 ThreadLocal 类形象的⽐喻成万能的钥匙,每个线程的都会维护 ThreadLocalMap 比喻成门,当拿万能的钥匙开的门不同得到的东西也不同。
- 如果创建了⼀个 ThreadLocal 变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是 ThreadLocal 变量名的由来。他们可以使⽤ get() 和 set() ⽅法来获取默认值或将其值更改为当前线程所存的副本的值,从⽽避免了线程安全问题。
- 每一个 Thread 中会维护 ThreadLocalMap,默认情况下是null,当前线程调⽤ ThreadLocal 类的 Set 或 Get ⽅法时才创建,ThreadLocal 类的set 或 get ⽅法实际上会调用ThreadLocalMap的 getEntry() 、set() ⽅法。最终的变量是放在了当前线程的 ThreadLocalMap中,并不是存在 ThreadLocal 上。
- Thread 内部维护的是⼀个类似 Map 的 ThreadLocalMap 数据结构。ThreadLocalMap 是 ThreadLocal 的静态内部类,ThreadLocalMap 里有一个 Entry数组存放数据。
- 先获取当前线程;
- 再获取当前线程的ThreadLocalMap;
- 如果这个ThreadLocalMap不为空,那么就把ThreadLocal作为为Key参数,调用ThreadLocalMap的getEntry() 方法,获取到对应value;
- 如果为空就创建当前线程的ThreadLocalMap,并把ThreadLocal为Key,val封装成一个Entry 放入ThreadLocalMap中;
- 先获取当前线程;
- 再获取当前线程的ThreadLocalMap;
- 如果这个ThreadLocalMap不为空,那么就把ThreadLocal为Key,传入的值作为value 封装成一个Entry 放入ThreadLocalMap中。
- 如果为空就创建当前线程的ThreadLocalMap,并把ThreadLocal为Key,null作为value 封装成一个Entry 放入ThreadLocalMap中。
- 如果key强引用指向threadlocal,也就是上图虚线那里是个弱引用,那么当这个Threadlocal没有其他引用指向它时,会因为和 entry 存在强引用导致无法被回收!造成内存泄漏。
- ThreadLocalMap 中使⽤的 key 为 ThreadLocal 的弱引用,⽽ value 是强引用;
- ThreadLocal 没有被外部强引⽤的情况下,在垃圾回收的时候,key 会被清理掉,⽽ value 不会
被清理掉。这样⼀来, ThreadLocalMap 中就会出现key为null的Entry。假如我们不做任何措施
的话,value 永远⽆法被GC 回收,这个时候就可能会产⽣内存泄露。 - ThreadLocalMap实现中已经考虑了这种情况,在调⽤ set() 、 get() 、 remove() ⽅法的时候,会清理掉 key 为 null 的记录。使⽤完ThreadLocal ⽅法后 最好⼿动调⽤ remove() ⽅法。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)