浅谈threadlocal
1.什么是threadlocal?
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
1、set方法源码
1 public void set(T value) { 2 //(1)获取当前线程(调用者线程) 3 Thread t = Thread.currentThread(); 4 //(2)以当前线程作为key值,去查找对应的线程变量,找到对应的map 5 ThreadLocalMap map = getMap(t); 6 //(3)如果map不为null,就直接添加本地变量,key为当前定义的ThreadLocal变量的this引用,值为添加的本地变量值 7 if (map != null) 8 map.set(this, value); 9 //(4)如果map为null,说明首次添加,需要首先创建出对应的map 10 else 11 createMap(t, value); 12 }
在上面的代码中,(2)处调用getMap方法获得当前线程对应的threadLocals(参照上面的图示和文字说明),该方法代码如下
ThreadLocalMap getMap(Thread t) { return t.threadLocals; //获取线程自己的变量threadLocals,并绑定到当前调用线程的成员变量threadLocals上 }
如果调用getMap方法返回值不为null,就直接将value值设置到threadLocals中(key为当前线程引用,值为本地变量);如果getMap方法返回null说明是第一次调用set方法(前面说到过,threadLocals默认值为null,只有调用set方法的时候才会创建map),这个时候就需要调用createMap方法创建threadLocals,该方法如下所示
1 void createMap(Thread t, T firstValue) { 2 t.threadLocals = new ThreadLocalMap(this, firstValue); 3 }
createMap方法不仅创建了threadLocals,同时也将要添加的本地变量值添加到了threadLocals中。
2、get方法源码
在get方法的实现中,首先获取当前调用者线程,如果当前线程的threadLocals不为null,就直接返回当前线程绑定的本地变量值,否则执行setInitialValue方法初始化threadLocals变量。在setInitialValue方法中,类似于set方法的实现,都是判断当前线程的threadLocals变量是否为null,是则添加本地变量(这个时候由于是初始化,所以添加的值为null),否则创建threadLocals变量,同样添加的值为null。
1 public T get() { 2 //(1)获取当前线程 3 Thread t = Thread.currentThread(); 4 //(2)获取当前线程的threadLocals变量 5 ThreadLocalMap map = getMap(t); 6 //(3)如果threadLocals变量不为null,就可以在map中查找到本地变量的值 7 if (map != null) { 8 ThreadLocalMap.Entry e = map.getEntry(this); 9 if (e != null) { 10 @SuppressWarnings("unchecked") 11 T result = (T)e.value; 12 return result; 13 } 14 } 15 //(4)执行到此处,threadLocals为null,调用该更改初始化当前线程的threadLocals变量 16 return setInitialValue(); 17 } 18 19 private T setInitialValue() { 20 //protected T initialValue() {return null;} 21 T value = initialValue(); 22 //获取当前线程 23 Thread t = Thread.currentThread(); 24 //以当前线程作为key值,去查找对应的线程变量,找到对应的map 25 ThreadLocalMap map = getMap(t); 26 //如果map不为null,就直接添加本地变量,key为当前线程,值为添加的本地变量值 27 if (map != null) 28 map.set(this, value); 29 //如果map为null,说明首次添加,需要首先创建出对应的map 30 else 31 createMap(t, value); 32 return value; 33 }
remove方法判断该当前线程对应的threadLocals变量是否为null,不为null就直接删除当前线程中指定的threadLocals变量
1 public void remove() { 2 //获取当前线程绑定的threadLocals 3 ThreadLocalMap m = getMap(Thread.currentThread()); 4 //如果map不为null,就移除当前线程中指定ThreadLocal实例的本地变量 5 if (m != null) 6 m.remove(this); 7 }
①强引用:Java中默认的引用类型,一个对象如果具有强引用那么只要这种引用还存在就不会被GC。
②软引用:简言之,如果一个对象具有弱引用,在JVM发生OOM之前(即内存充足够使用),是不会GC这个对象的;只有到JVM内存不足的时候才会GC掉这个对象。软引用和一个引用队列联合使用,如果软引用所引用的对象被回收之后,该引用就会加入到与之关联的引用队列中
③弱引用(这里讨论ThreadLocalMap中的Entry类的重点):如果一个对象只具有弱引用,那么这个对象就会被垃圾回收器GC掉(被弱引用所引用的对象只能生存到下一次GC之前,当发生GC时候,无论当前内存是否足够,弱引用所引用的对象都会被回收掉)。弱引用也是和一个引用队列联合使用,如果弱引用的对象被垃圾回收期回收掉,JVM会将这个引用加入到与之关联的引用队列中。若引用的对象可以通过弱引用的get方法得到,当引用的对象呗回收掉之后,再调用get方法就会返回null
④虚引用:虚引用是所有引用中最弱的一种引用,其存在就是为了将关联虚引用的对象在被GC掉之后收到一个通知。(不能通过get方法获得其指向的对象)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)