使用ThreadLocal注意事项

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.csdn.net/raylee2007/article/details/51683805?%3E

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值