threadlocal

83 阅读2分钟
java对象的引用类型?
  • 强【Object o = new Object()】
  • 软【softreference,一个对象只有弱引用的情况下,只有在内存不足的情况下,被引用的对象才会被回收】
  • 弱【weakreference,一个对象只有弱引用的情况下,引用的对象只要垃圾回收执行,就会被回收,而不管是否内存不足】
  • 虚【phantomReference,GC回收,虚引用的对象被回收,虚引用会被加入到ReferenceQueue中,通知应用程序对象的回收情况】
threadLocal?

截屏2024-04-03 09.33.29.png

  • threadLocal对象的声明一般设置为静态属性,这种情况下threadLocal对象的强引用一直存在
threadLocal 内存泄漏的场景
  • tl的强引用一直存在
  • t与t1的线程一直存在
  • t与t1不调用remove,key和value将会一直存在,这里其实最大的问题是使用完成后value一直存在
为什么若引用能够一定程度上解决若引用?
  • threadlocal没有强引用 【线程结束时释放threadlocal的强引用/threadlocal对象对象在方法中创建且没有将它返回或者赋值给其他变量】
  • t与t1的线程一直存在
  • t与t1不调用remove,因为threadlocal只有若引用,就会被回收,这里其实解决的是key一直存在的问题
public class ThreadLocalSample {
    public static void main(String[] args) throws InterruptedException {
        ThreadLocalSample threadLocalSample = new ThreadLocalSample();
        ArrayBlockingQueue<Runnable> runnables = new ArrayBlockingQueue<Runnable>(100);
        int max=1,min = 1;
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(min, max,1000, TimeUnit.SECONDS, runnables);
        threadPoolExecutor.execute(threadLocalSample::useThreadLocal);
        TimeUnit.SECONDS.sleep(5);
        System.out.println("准备GC");
        System.gc();
        System.out.println("GC 完成");
        threadPoolExecutor.execute(()->{
            Thread thread = Thread.currentThread();
            //#1
            System.out.println("debug看看上面的线程threadLocalMap属性中是否有值");
        });

        TimeUnit.SECONDS.sleep(1000);
    }
    void useThreadLocal(){
        ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
        stringThreadLocal.set("aaaaa");
        System.out.println("use threadLocal complete");

    }

}
debug在#1处查看thread的threadLocalMap中的key 已经不存在了,即使我没有调用remove。个人认为实际上没有人会这么用threadLocal,这个若引用很鸡肋。
threadLocal的使用场景?
  • 共享变量的多线程隔离场景【多线程下的方法参数多级传递,如果不想修改参数列表可以使用threadLocal】
  • spring多数据源
  • 日志追踪,MDC中traceId
如何解决thradLocal的泄漏?
  • 尽量使用static final 修饰,禁止修改饮用
  • 使用完成threadlocal之后,try finally 中调用remove
父子线程如何共享数据
  • 使用InhertitableThreadlocal,Thread中保存了InhertitableThreadlocal的成员变量在init的方法中会cp父线程的设置的值,也就是说,只有创建新线程的那一刻进行复制
  • 如果是线程池那依然获取不到,因为init方法在线程创建的时候执行过了
线程池中如何额共享数据
  • 阿里巴巴的transmittable-thread-local.jar 中的transmittableThreadlocal