使用ThreadLocal注意事项

本文深入探讨了ThreadLocal的使用场景及注意事项,特别是get方法遇到null值的问题及其解决方案,并讨论了如何避免内存泄漏和脏数据产生的风险。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ThreadLocal主要的使用是get、set、initialValue这几个方法

需要注意两个事项:

  1. 在get方法的时候出现null
  2. 内存泄漏或产生脏数据

1、在get方法的时候出现null

package com.ray.deepintothread.ch04.topic_3;

public class ThreadLocalGetNull {
    private int count = 0;
    public ThreadLocal<Integer> intThreadLocal = new ThreadLocal<Integer>();

    public int getCount() {
        return intThreadLocal.get();
    }

    public void addCount() {
        intThreadLocal.set(count++);
    }

	//测试
    public static void main(String[] args) {
        System.out.println(new ThreadLocalGetNull().getCount());
    }
}

输出:

Exception in thread “main” java.lang.NullPointerException
at com.ray.deepintothread.ch04.topic_3.ThreadLocalGetNull.getCount(ThreadLocalGetNull.java:10)
at com.ray.deepintothread.ch04.topic_3.ThreadLocalGetNull.main(ThreadLocalGetNull.java:18)

解决方案:使用initialValue方法初始化

package com.ray.deepintothread.ch04.topic_3;

public class SolutionOfThreadLocalGetNull {
    private int count = 0;

    public ThreadLocal<Integer> intThreadLocal = new ThreadLocal<Integer>() {
        // 解决办法就是初始化数值
        @Override
        protected Integer initialValue() {
            return count;
        }
    };

    public int getCount() {
        return intThreadLocal.get();
    }

    public void addCount() {
        intThreadLocal.set(count++);
    }

	//测试
    public static void main(String[] args) {
        System.out.println(new SolutionOfThreadLocalGetNull().getCount());
    }
}

输出:

0

在定义ThreadLocal之初就通过initialValue方法初始化返回的值。

 2、内存泄漏或产生脏数据

  • 使用ThreadLocal时,会在线程的私有的Map对象中存储对应的变量值Value,对应的key为ThreadLocal对象本身。当线程为普通线程执行完逻辑就销毁时,Map对象会被回收。                                                                                        当线程为线程池线程时,执行完任务后,线程并没有销毁所以Map对象任然存在,且里面的内容Value没有被删除。执行的次数多了后,就会产生内存泄漏。
  • 当线程再次使用之前的ThreadLocal对象获取值时能获取到对应的Value,但这个值是上一次设置进去的,本次并没有设置Value值。所以也会产生脏数据。

对于ThreadLocal使用前或者使用后一定要先remove。

private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(2);
    for (int i = 0; i < 5; i++) {
        executorService.execute(()-> {
            try {
                Integer before = threadLocal.get();
                threadLocal.set(before + 1);
                Integer after = threadLocal.get();
                System.out.println("before: " + before + ",after: " + after);
            } finally {
                threadLocal.remove();
            }
        });
    }
    executorService.shutdown();
}

参考:

https://blog.youkuaiyun.com/raylee2007/article/details/51683805?%3E

https://www.cnblogs.com/huacheng/p/12609435.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值