四种引用类型 + ThreadLocal理解

四种引用

强引用

只要引用链不断,就不会被回收

User user = new User();

软引用 在缓存中使用

SoftReference;

内存不足的时候,会回收

在内存快要OOM的时候,进行释放

否则:尽管调用System.gc(),也不会释放

-Xms10m -Xmx10m -XX+PrintGC

弱引用 很少使用的对象,使用弱引用,不重要的对象

GC到的时候回收,回收

WeakReference()

虚引用(幽灵) 一般和一个对象进行绑定,当GC回收这个对象的时候,可以得到一个消息

PhantomReference()

ThreadLocal

1、ThreadLocal是线程内部的存储类,存储的数据,只有指定线程可以得到促成农户数据

2、ThreadLocal提供了线程内存储变量的能力

3、ThreadLocal维护一个Map,key是当前线程,value是存储的对象

4、ThreadLocal的静态内部类ThreadLocalMap为每一个Thread都维护一个数组table。ThreadLocal确定数组下标,

//set 方法
public void set(T value) {
      //获取当前线程
      Thread t = Thread.currentThread();
      //实际存储的数据结构类型
      ThreadLocalMap map = getMap(t);
      //如果存在map就直接set,没有则创建map并set
      if (map != null)
          map.set(this, value);
      else
          createMap(t, value);
  }
  
//getMap方法
ThreadLocalMap getMap(Thread t) {
      //thred中维护了一个ThreadLocalMap
      return t.threadLocals;
 }
 
//createMap
void createMap(Thread t, T firstValue) {
      //实例化一个新的ThreadLocalMap,并赋值给线程的成员变量threadLocals
      t.threadLocals = new ThreadLocalMap(this, firstValue);
}

每个线程持有一个ThreadLocalMap

每个线程都会实例化一个ThreadLocalMap然后赋值给ThreadLocal.ThreadLocalMap threadLocals = null;

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
}
//Entry为ThreadLocalMap静态内部类,对ThreadLocal的弱引用
//同时让ThreadLocal和储值形成key-value的关系
static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
           super(k);
            value = v;
    }
}

//ThreadLocalMap构造方法
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
        //内部成员数组,INITIAL_CAPACITY值为16的常量
        table = new Entry[INITIAL_CAPACITY];
        //位运算,结果与取模相同,计算出需要存放的位置
        //threadLocalHashCode比较有趣
        int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
        table[i] = new Entry(firstKey, firstValue);
        size = 1;
        setThreshold(INITIAL_CAPACITY);
}

每个线程Thread持有一个ThreadLocalMap类型的实例threadLocals,结合此处的构造方法可以理解成每个线程Thread都持有一个Entry型的数组table,

ThreadLocalMap里的Entry数组存储ThreadLocal

位置确定 ThreadLocalHashCode key:ThreadLocal value:存储的值

总结

1、对于某一ThreadLocal来讲,他的索引值i是确定的,在不同线程之间访问时访问的是不同的table数组的同一位置即都为table[i],只不过这个不同线程之间的table是独立的。

2、对于同一线程的不同ThreadLocal来讲,这些ThreadLocal实例共享一个table数组,然后每个ThreadLocal实例在table中的索引i是不同的。

3、Entry中的key ThreadLocal是弱引用,value是正常的 。GC时候,ThreadLocal被GC,key为null,value是强引用,线程一直存在的话,value旧不会被回收,造成内存泄漏。但是调用get、set、remove方法的时候,都会对key为null 的数据进行清除。如果不调用,就会存在内存泄漏。

ThreadLocal特性:

ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题,不同的点是

  • Synchronized是通过线程等待,牺牲时间来解决访问冲突
  • ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。

正因为ThreadLocal的线程隔离特性,使他的应用场景相对来说更为特殊一些。在android中Looper、ActivityThread以及AMS中都用到了ThreadLocal。当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值