面试题答案
一键面试原因分析
- 弱引用问题:
ThreadLocal
内部使用ThreadLocalMap
来存储数据,ThreadLocalMap
的Entry
对ThreadLocal
是弱引用。当ThreadLocal
对象在其他地方不再被强引用时,在垃圾回收时,ThreadLocal
会被回收。但此时ThreadLocalMap
中的Entry
的key
为null
,而value
依然存在强引用。如果当前线程一直存活,这个Entry
就无法被回收,导致内存泄漏。 - 线程复用:在使用线程池等场景下,线程会被复用。如果在线程执行任务过程中使用了
ThreadLocal
,任务执行完后没有清理ThreadLocal
的值,当这个线程再次被使用时,之前ThreadLocal
残留的值依然占用内存,可能导致内存泄漏。
代码层面避免内存泄漏方法
- 手动调用
remove()
方法:在使用完ThreadLocal
后,手动调用remove()
方法,清除ThreadLocalMap
中对应的Entry
。
示例代码
public class ThreadLocalExample {
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
threadLocal.set("Some value");
// 业务逻辑
System.out.println("ThreadLocal value: " + threadLocal.get());
} finally {
// 避免内存泄漏,手动调用remove方法
threadLocal.remove();
}
});
thread.start();
}
}
分析
在上述代码中,try - finally
块确保了无论业务逻辑执行过程中是否出现异常,都会在最后调用threadLocal.remove()
方法。这样当ThreadLocal
对象不再被需要时,ThreadLocalMap
中对应的Entry
会被清理,避免了因ThreadLocal
对象被回收但Entry
残留导致的内存泄漏。如果不调用remove()
方法,当ThreadLocal
对象失去强引用被垃圾回收后,ThreadLocalMap
中key
为null
但value
存在强引用的Entry
将一直存在,随着线程的长期存活或线程复用,可能导致内存泄漏。