前沿

可先参考之前写的 https://www.yuque.com/u1687194/hspkbf/uvaeep

概览

image.png

代码

源码

  1. class Thread {
  2. //内部持有ThreadLocalMap
  3. ThreadLocal.ThreadLocalMap threadLocals;
  4. }
  5. class ThreadLocal<T> {
  6. public T get() {
  7. //首先获取线程持有的
  8. //ThreadLocalMap
  9. ThreadLocalMap map = Thread.currentThread().threadLocals;
  10. //在ThreadLocalMap中
  11. //查找变量
  12. Entry e = map.getEntry(this);
  13. return e.value;
  14. }
  15. static class ThreadLocalMap {
  16. //内部是数组而不是Map
  17. Entry[] table;
  18. //根据ThreadLocal查找Entry
  19. Entry getEntry(ThreadLocal key) {
  20. //省略查找逻辑
  21. }
  22. //Entry定义
  23. static class Entry extends WeakReference<ThreadLocal> {
  24. Object value;
  25. }
  26. }
  27. }

使用demo

  1. public class BaseTest {
  2. ThreadLocal<Long> longLocal = new ThreadLocal<>();
  3. ThreadLocal<String> stringLocal = new ThreadLocal<>();
  4. public void set() {
  5. longLocal.set(Thread.currentThread().getId());
  6. stringLocal.set(Thread.currentThread().getName());
  7. }
  8. public long getLong() {
  9. return longLocal.get();
  10. }
  11. public String getString() {
  12. return stringLocal.get();
  13. }
  14. }

Entry的key为什么要使用弱引用

ThreadLocal - 图2
每个thread中都有一个map成员变量(类型是ThreadLocal.ThreadLocalMap)。map中的key为一个个Threadlocal实例。 这个Map的确使用了弱引用,不过弱引用只是针对key。每个key都弱引用指向Threadlocal实例。所以当把Threadlocal实例置为null以后(或者说方法块执行完了之后,其内部的申明的new ThreadLocal实例)理应被释放了。但由于当前线程还存活,作为GCRoot扫描来说,ThreadLocalMap也存活,里面的key又是引用了已经实际无效的被释放的Threadlocal
注意!假如每个key都强引用指向threadlocal,也就是上图虚线那里是个强引用,那么这个threadlocal就会因为和entry存在强引用无法被回收!造成内存泄漏 ,除非线程结束,线程被回收了,map也跟着回收。

依然出现的内存泄露问题

虽然上述的弱引用解决了key,也就是线程的ThreadLocal能及时被回收,但是value却依然存在内存泄漏的问题。
当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal将会被gc回收.
map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露,
因为存在一条从current thread连接过来的强引用.
只有当前thread结束以后, current thread就不会存在栈中,强引用断开, Current Thread, Map, value将全部被GC回收.

参考

【1】什么是ThreadLocal ?:https://mp.weixin.qq.com/s?src=11&timestamp=1633704856&ver=3362&signature=hvSCHM9ekL9BmHd8a9Thi84l1R8EUVk8DcqCnsjA8hFMtQlW9rTI-XJ28MYndo49Aj9CH2dukKOtuQioVLSWZDZXGymDf8MGfuTkzUwZ8ZtbErFn3iwMMsrsobnhTM&new=1