强软弱引用,ThreadLocal和内存泄漏

强引用

写法:Object obj=new Object()
引用强度:最强
只要被引用着,就不会被gc(垃圾回收)回收掉。

软引用

写法:SoftReference<String> sr = new SoftReference<String>(new String("软"));
引用强度:第二
如果内存不足时,就会回收掉软引用,适用于缓存。

弱引用

写法:WeakReference<String> wr = new WeakReference<String>(new String("弱"));;
引用强度:第三
当JVM进行垃圾回收的时候,无论内存是否充足都会将其回收掉。

ThreadLocal简介

ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量,例如A线程给类对象赋值在A线程中可以输出,在B线程中再去输出这个对象的值就会是null。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

ThreadLocal源码

set方法
public void set(T value) {
    //获取到当前线程
    Thread t = Thread.currentThread();
    //从当前线程获取Map
    ThreadLocalMap map = getMap(t);
    if (map != null)
       //如果当前map不为空继续存,this为ThreadLocal对象,value就是传进来的值
       map.set(this, value);
    else
       //为空就创建一个新的ThreadLocalMap
       createMap(t, value);
}
map.set方法中
private void set(ThreadLocal<?> key, Object value) {

       Entry[] tab = table;
       int len = tab.length;
       int i = key.threadLocalHashCode & (len-1);

       for (Entry e = tab[i];
           e != null;
           e = tab[i = nextIndex(i, len)]) {
           ThreadLocal<?> k = e.get();

           if (k == key) {
              e.value = value;
              return;
           }

           if (k == null) {
              replaceStaleEntry(key, value, i);
              return;
           }
        }
        //可以理解为一个Entry就等于一个键值对
        tab[i] = new Entry(key, value);
        int sz = ++size;
        if (!cleanSomeSlots(i, sz) && sz >= threshold)
           rehash();
}
Entry方法
//继承了弱引用
static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal<?> k, Object v) {
      //调用了父类的构造
      super(k);
      value = v;
   }
}


ThreadLocal之内存泄漏

内存泄漏:是指一个用不到对象在内存中强引用着,也清理不掉,无法释放就会占用内存资源。
内存溢出:是指一直在内存中存放强引用对象,也回收不掉就会存放满导致溢出。
为什么ThreadLocal的Entry是弱引用?因为如果是强引用,即使ThreadLocal local = null,但key依然指向ThreadLocal对象,ThreadLocal对象不会被回收,导致内存泄漏。而弱引用,ThreadLocal对象会被回收掉。但是,ThreadLocal对象被回收掉,key = null,value永远不会被访问到,所以依然存在内存泄漏的问题。解决方法是,使用ThreadLocal.set设置值,使用完之后,要调用remove方法移除。

ThreadLocal应用场景

ThreadLocal在Spring框架中,用于实现声明式事务。开启事务后,将从连接池中拿到的数据库连接,存放到ThrealLocal中,保证事务中的所有数据库操作都是从ThreadLocal中拿到同一个数据库连接。
posted @ 2022-04-11 22:40  橙香五花肉  阅读(172)  评论(0编辑  收藏  举报