ThreadLocal和强软弱虚引用

  • Post author:
  • Post category:其他





1 四种引用类型

Java将引用分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种类型,每种引用强度依次逐渐减弱。



1.1 强引用

强引用即普遍意义上的引用,比如:Object o = new Object(),这里o就是一个强引用,只要这个引用关系存在,对象永远不会被回收,即使内存不足,JVM只会抛出OOM异常。



1.2 软引用

软引用用来指向一些后续可能会使用到但并非必须存在的对象,比如创建一个软引用:new SoftReference<>(new ArrayList<>()),这个软引用指向一个ArrayList对象。在系统将要发生OOM异常前,会把这个ArrayList对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出OOM异常。

根据软引用这个特性,可将其使用于缓存的场景。



1.3 弱引用

弱引用WeakReference和软引用类似,也是用来指向那些非必须的对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾回收发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用指向的对象。

弱引用在JDK中典型的应用有ThreadLocal。



1.4 虚引用

虚引用PhantomReference和弱引用一样也是发现即回收,其一般是用来管理堆外内存(直接内存)。



2 ThreadLocal



2.1 ThreadLocal源码解读

public class TestThreadLocal {
    public static void main(String[] args) throws InterruptedException {
        ThreadLocal<String> local = new ThreadLocal<>();
        new Thread(() -> local.set("Kitty")).start();
        Thread.sleep(2000);
        new Thread(() -> System.out.println(local.get())).start();
    }
}
输出:
null

上面的代码中,第二个线程并没有输出Kitty而是输出了null。通过查看ThreadLocal.set()方法:

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

可以看到ThreadLocal的set方法,是将value保存到当前线程中的一个key-value存储结构ThreadLocalMap中,key为ThreadLocal对象,value即set的值。所以一个线程调用ThreadLocal的set方法设置值之后,其他的线程通过get方法取不到值是理所当然的。以下是ThreadLocal在Thread中的示意图:

在这里插入图片描述



2.2 ThreadLocal之内存泄漏

为什么ThreadLocal的Entry是弱引用?因为如果是强引用,即使ThreadLocal local = null,但key依然指向ThreadLocal对象,ThreadLocal对象不会被回收,导致内存泄漏。而弱引用,ThreadLocal对象会被回收掉。但是,ThreadLocal对象被回收掉,key = null,value永远不会被访问到,所以依然存在内存泄漏的问题。解决方法是,使用ThreadLocal.set设置值,使用完之后,要调用remove方法移除。



2.3 ThreadLocal应用场景

ThreadLocal在Spring框架中,用于实现声明式事务。开启事务后,将从连接池中拿到的数据库连接,存放到ThrealLocal中,保证事务中的所有数据库操作都是从ThreadLocal中拿到同一个数据库连接。



版权声明:本文为qq_24358759原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。