ThreadLocal学习笔记
什么是ThreadLocal
ThreadLocal是线程变量,ThreadLocal中放的变量是属于当前线程的,该变量对于其他线程而言是隔离的。ThreadLocal为变量在每个线程中创建一个副本,每个线程可以访问自己线程内的副本。
ThreadLocal的优势:
- 进行对象跨层传递时,使用ThreadLocal可以避免多层传递,在ThreadLocal中存取数据即可;
- 线程间的数据隔离,每个线程维护自己的变量,对其他线程不可见;
ThreadLocal示例
package com.ludk.study.threadlocal;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author ludengke
* @title: ThreadLocalTest
* @projectName weixin
* @description: TODO
* @date 2023/11/1816:09
*/
public class ThreadLocalTest {
public static void main(String[] args) {
testThreadLocal();
}
public static void testThreadLocal(){
//线程变量,每个线程都有自己的变量副本
final ThreadLocal<String> local=new ThreadLocal<String>();
//启动了5个线程,线程的名字为线程finalI。local为线程外的公共变量,正常情况线程不安全。
//可因为他是ThreadLocal,每个线程都有自己的变量副本,因此打印结果是线程名称和线程自己的变量。
for (int i=0;i<5;i++){
final int finalI = i;
new Thread(new Runnable() {
public void run() {
local.set(finalI +"啊啊啊");
System.out.println(Thread.currentThread().getName()+":"+local.get());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"线程"+finalI+":").start();
}
}
}
线程0::0啊啊啊
线程3::3啊啊啊
线程2::2啊啊啊
线程1::1啊啊啊
线程4::4啊啊啊
Process finished with exit code 0
ThreadLocal的原码分析
ThreadLocal的设计关注三个点
- ThreadLocal
- ThreadLocalMap
- Thread
先上结论:
- Thread
每个线程都有自己的ThreadLocalMap - ThreadLocalMap
key ThreadLocal
value 值
比如有的地方定义了“sessionThreadLocal”,有的地方定义了“dataThreadLocal”,那ThreadLocalMap中就存储了这两个值,而且这两个值只属于当前线程,因为一个线程有自己对于的ThreadLocalMap
java.lang.ThreadLocal set
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取ThreadLoclMap
ThreadLocalMap map = getMap(t);
if (map != null)//如果获取到ThreadLocalMap,则放入数据,key为ThreadLocal,value为值
map.set(this, value);
else
//否则创建ThreadLocalMap
createMap(t, value);
}
从creatMap方法及下面图片的代码可以看出,每个线程会有自己的ThreadLocalMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
通过ThreadLocalMap的构造方法可以看出,ThreadLocalMap的key是ThreadLocl,value是想存储的值
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
ThreadLocalMap是ThreadLocal的静态内部类,是真正存储线程变量的地方
其他方法如remove可以自己分析。
ThreadLocal的应用场景
每个线程需要自己单独的变量,这种场景均可以考虑ThreadLocal
- 存储用户session
- 存储数据库连接
- 数据跨层传递
- 解决线程安全问题:但是他与synchronized有很大的区别。synchronized是加锁,某个安全点内,只有一个线程可以访问变量。而ThreadLocal是每个线程都有自己的变量,线程间的变量是隔离开的。