ThreadLocal基本使用
保证多个线程对变量访问的安全,将变量放到ThreadLocal类型的对象中,使变量在每个线程中都有独立值,不会出现一个线程读取变量时被另一个线程修改的现象。
使用示例
public class testThreadLocal {
public static void main(String[] args) {
ThreadLocal<String> local = new ThreadLocal<>();
Random random = new Random();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
local.set(Thread.currentThread().getName()+"......"+ random.nextInt(10));
System.out.println("线程和local值分别是"+local.get());
local.remove();
}
}).start();
}
}
}
使用场景:
- 线程隔离,ThreadLocal的数据只属于当前线程,多线程情况下可以防止自己的变量被其他线程篡改,常用案例,每个线程绑定一个用户会话信息,数据库连接,HTTP请求等,这样每个线程调用到的处理函数都可以非常方便的访问这些资源。数据库连接独享,Session数据管理
- 跨函数传递数据,同一个线程内跨类,夸方法传递数据时,如果不用ThreadLocal,那么相互之间的数据传递势必要靠返回值和参数,增加了这些类或方法的耦合度。
推荐使用static final修饰ThreadLocal 对象 被所有对象共享,防止使用过程中发生动态变更;
源码分析
- Thread类有一个threadLocals 变量 使用默认访问控制修饰符,包内可见
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
// 翻译下:此线程相关的本地变量值,此map由ThreadLocal类维护,初始值为空
ThreadLocal.ThreadLocalMap threadLocals = null;
- ThreadLocal类结构

- set(T value) 方法
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取线程的map
ThreadLocalMap map = getMap(t);
//value值方入map
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//根据线程对象获取其属性 threadLocals
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//创建ThreadLocalMap 对象
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
- get() 方法
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
// 根据threadLocal对象获取 Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//如果map为空 返回初始值null
return setInitialValue();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
protected T initialValue() {
return null;
}
- remove() 方法
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
内容泄露问题:
-
map中的key为什么是弱引用?
线程执行过程,调用栈内变量t 强引用指向 堆内对象LocalThread 而线程中threalocaltMap 中的key是弱引用ThreadLocal对象,不能是强引用,会造成内容泄露;因为线程执行完成 栈内变量t会销毁,但线程不一定会销毁,线程中的threadlocalmap对应也不一定会销毁,造成内存泄漏,此时如果key是强引用ThreadLocal对象,则ThreadLocal对象无法销毁,LocalThread对象不能被垃圾回收,故一定要弱引用; -
线程变量使用完后,使用remove清除 map中的value,避免内存泄漏
728

被折叠的 条评论
为什么被折叠?



