ThreadLocal主要的使用是get、set、initialValue这几个方法
需要注意两个事项:
- 在get方法的时候出现null
- 内存泄漏或产生脏数据
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