ThreadLocal
2023年11月15日大约 4 分钟约 751 字
线程数据共享和安全-ThreadLocal
介绍
- ThreadLocal 的作用,可以实现在同一个线程数据共享, 从而解决多线程数据安全问题. 2. ThreadLocal 可以给当前线程关联一个数据(普通变量、对象、数组)set 方法 [源码!]
- ThreadLocal 可以像 Map 一样存取数据,key 为当前线程, get 方法
- 每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例
- 每个 ThreadLocal 对象实例定义的时候,一般为 static 类型
- ThreadLocal 中保存数据,在线程销毁后,会自动释放

快速入门
package com.lzw.threadlocal;
public class T2DAO {
public void update() {
//取出线程关联的threadLocal1对象的数据
Object o = T1.threadLocal1.get();
//获取当前线程名
String name = Thread.currentThread().getName();
System.out.println("在T2DAO的update() 线程是= " + name + " 取出dog=" + o);
}
}
package com.lzw.threadlocal;
public class T1Service {
public void update(){
//取出 threadLocal1 关联的对象
/**解读源码
* * public T get() {
* //1. 先得到当前的线程对象
* Thread t = Thread.currentThread();
* //2.通过线程获取到对应的ThreadLocalMap
* ThreadLocalMap map = getMap(t);
* if (map != null) {
* //3. 如果map不为空, 根据当前的 threadlocal对象,得到对应的Entry
* ThreadLocalMap.Entry e = map.getEntry(this);
* //4. 如果e 不为null
* if (e != null) {
* @SuppressWarnings("unchecked")
* //返回当前threadlocal关联的数据value
* T result = (T)e.value;
* return result;
* }
* }
* return setInitialValue();
* }*
*/
Object o = T1.threadLocal1.get();
//获取当前线程名
String name = Thread.currentThread().getName();
System.out.println("在T1Service的update() 线程name= " + name + " dog= " + o);
//调用dao-update
new T2DAO().update();
}
}
package com.lzw.threadlocal;
public class T1 {
//创建ThreadLocal对象,做成public static.
public static ThreadLocal<Object> threadLocal1 = new ThreadLocal<>();
public static ThreadLocal<Object> threadLocal2 = new ThreadLocal<>();
//Task 是线程类 -> 内部类 / 线程
public static class Task implements Runnable {
@Override
public void run() {
Dog dog = new Dog();
Pig pig = new Pig();
//给threadLocal1 对象放入set dog , 隔山打牛
System.out.println("Task 放入了 dog= " + dog);
/**
解读源码
public void set(T value) {
//1. 获取当前线程, 关联到当前线程!
Thread t = Thread.currentThread();
//2. 通过线程对象, 获取到ThreadLocalMap
// ThreadLocalMap 类型 ThreadLocal.ThreadLocalMap
ThreadLocalMap map = getMap(t);
//3. 如果map不为null, 将数据(dog,pig..) 放入map -key:threadLocal value:存放的数据
// 从这个源码我们已然看出一个threadlocal只能关联一个数据,如果你set, 就会替换
//4. 如果map为null, 就创建一个和当前线程关联的ThreadLocalMap, 并且该数据放入
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
*/
threadLocal1.set(dog);
//threadLocal1.set(pig);
threadLocal2.set(pig);
System.out.println("Task 在run 方法中 线程=" + Thread.currentThread().getName());
new T1Service().update();
}
}
public static void main(String[] args) {
new Thread(new Task()).start();//主线程启动一个新的线程,注意不是主线程
}
}
原理分析

public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
/*********************/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

