Java源码解析:ThreadLocal
2021/7/17 20:06:08
本文主要是介绍Java源码解析:ThreadLocal,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
本文由colodoo(纸伞)整理
参考源码:jdk1.8.0_131
我相信大部分的人对ThreanLocal都一脸懵逼的,因为我一开始也是这样的,直到在面试中被问到以后,我才第一次知道ThreanLocal的存在。
这是一些结论性的介绍,足以应付面试题:
- ThreadLocal是Java中所提供的线程本地存储机制,可以利⽤该机制将数据缓存在某个线程内部,该线
程可以在任意时刻、任意⽅法中获取缓存的数据- ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象(注意不是ThreadLocal
对象)中都存在⼀个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓
存的值- 如果在线程池中使⽤ThreadLocal会造成内存泄漏,因为当ThreadLocal对象使⽤完之后,应该
要把设置的key,value,也就是Entry对象进⾏回收,但线程池中的线程不会回收,⽽线程对象
是通过强引⽤指向ThreadLocalMap,ThreadLocalMap也是通过强引⽤指向Entry对象,线程
不被回收,Entry对象也就不会被回收,从⽽出现内存泄漏,解决办法是,在使⽤了
ThreadLocal对象之后,⼿动调⽤ThreadLocal的remove⽅法,⼿动清楚Entry对象- ThreadLocal经典的应⽤场景就是连接管理(⼀个线程持有⼀个连接,该连接对象可以在不同的⽅法之
间进⾏传递,线程之间不共享同⼀个连接)
然后再从源码的角度来解释这些结论。
set
java.lang.ThreadLocal#set
public void set(T value) { // 获取当前线程 Thread t = Thread.currentThread(); // 获取线程中的线程本地存储对象 ThreadLocalMap map = getMap(t); // 如果存在,则设置值 if (map != null) map.set(this, value); else // 不存在则创建本地存储对象,并设置值 createMap(t, value); }
- 获取当前线程
- 获取当前线程中的本地存储对象
- 把值设置到当前线程的本地存储对象中
从这里就可以看出,ThreadLocal作用域是当前线程(currentThread),不同线程之间是隔离的。
set
java.lang.ThreadLocal.ThreadLocalMap#set
private void set(ThreadLocal<?> key, Object value) { // Entry数组赋值给临时变量tab Entry[] tab = table; // 获取Entry数组长度 int len = tab.length; // 根据key通过hash算法获取下标 int i = key.threadLocalHashCode & (len-1); // 遍历Entry数组 for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); // 如果存在则更新 if (k == key) { e.value = value; return; } // 替换陈旧条目 // TODO:这里的逻辑复杂不深究 if (k == null) { replaceStaleEntry(key, value, i); return; } } // 否则新增节点 tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
getMap
java.lang.ThreadLocal#getMap
ThreadLocalMap getMap(Thread t) { // 获取线程中的ThreadLocalMap return t.threadLocals; }
createMap
java.lang.ThreadLocal#createMap
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
ThreadLocalMap
java.lang.ThreadLocal.ThreadLocalMap#ThreadLocalMap(java.lang.ThreadLocal<?>, java.lang.Object)
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { // 实例化Entry数组 table = new Entry[INITIAL_CAPACITY]; // 计算下标 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); // 新增节点到数组中 table[i] = new Entry(firstKey, firstValue); // 设置尺寸=1 size = 1; // 设置阈值 setThreshold(INITIAL_CAPACITY); }
get
java.lang.ThreadLocal#get
public T get() { // 获取当前线程 Thread t = Thread.currentThread(); // 获取当前线程ThreadLocalMap ThreadLocalMap map = getMap(t); // 如果ThreadLocalMap不为空 if (map != null) { // 获取Entry ThreadLocalMap.Entry e = map.getEntry(this); // 获取结果不为空,返回结果 if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } // 否则设置初始化值 return setInitialValue(); }
图解
以下为帮助记忆的一张图。
这篇关于Java源码解析:ThreadLocal的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-01后台管理开发学习:新手入门指南
- 2024-11-01后台管理系统开发学习:新手入门教程
- 2024-11-01后台开发学习:从入门到实践的简单教程
- 2024-11-01后台综合解决方案学习:从入门到初级实战教程
- 2024-11-01接口模块封装学习入门教程
- 2024-11-01请求动作封装学习:新手入门教程
- 2024-11-01登录鉴权入门:新手必读指南
- 2024-11-01动态面包屑入门:轻松掌握导航设计技巧
- 2024-11-01动态权限入门:新手必读指南
- 2024-11-01动态主题处理入门:新手必读指南