18.1 什么是 ThreadLocal
- ThreadLocal 的作用,可以实现在同一个线程数据共享,从而解决多线程数据安全问题
- ThreadLocal 可以给当前线程关联一个数据 (普通变量、对象、数组) set 方法
- ThreadLocal 可以像 Map 一样存取数据,key 为当前线程,get 方法
- 每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例
- 每个 ThreadLocal 对象实例定义的时候,一般为 static 类型
- ThreadLocal 中保存数据,在线程销毁后,会自动释放
18.2 快速入门 ThreadLocl
● 需求: 演示 ThreadLocal (作用:在一个线程中, 共享数据(线程安全))的使用-画图
● 代码实现
- 创建 Dog.java
package com.xjs.threadlocal;
/**
* @Author: 谢家升
* @Date: 2022/3/28-03-28-21:41
* @Version: 1.0
*/
public class Dog {
}
- 创建 Pig.java
package com.xjs.threadlocal;
/**
* @Author: 谢家升
* @Date: 2022/3/28-03-28-21:41
* @Version: 1.0
*/
public class Pig {
}
- 创建 T2DAO.java
package com.xjs.threadlocal;
/**
* @Author: 谢家升
* @Date: 2022/3/28-03-28-21:42
* @Version: 1.0
*/
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);
}
}
- 创建 T1Service.java
package com.xjs.threadlocal;
/**
* @Author: 谢家升
* @Date: 2022/3/28-03-28-21:43
* @Version: 1.0
*/
public class T1Service {
public void update() {
//取出 threadLocal1 对象关联的dog对象
/**
* 解读 :threadLocal1.get();
*
* public T get() {
* //1.先得到当前的线程对象
* Thread t = Thread.currentThread();
* //2.通过当前线程获取到对应的 ThreadLocalMap
* ThreadLocalMap map = getMap(t);
* if (map != null) {
* //3.如果这个 map不为null,就根据当前调用者(此处就是threadLocal1对象),得到对应的Entry
* ThreadLocalMap.Entry e = map.getEntry(this);
* if (e != null) {
* @SuppressWarnings("unchecked")
* //4.如果 Entry 不为null,就返回当前 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 + " dog=" + o);
//调用了 T2DAO 的 update() 方法
new T2DAO().update();
}
}
- 创建 T1.java
package com.xjs.threadlocal;
import java.security.PublicKey;
/**
* @Author: 谢家升
* @Date: 2022/3/28-03-28-21:21
* @Version: 1.0
*/
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);
/*
阅读源码:threadLocal1.set(dog);
public void set(T value) {
//1. 获取当前线程,关联到当前线程
Thread t = Thread.currentThread();
//2. 通过线程对象 t ,获取到 ThreadLocalMap
// ThreadLocalMap 是 threadLocal1 里面的一个静态内部类
ThreadLocalMap map = getMap(t);
//3. 如果 map 不为null,将 数据(dog,pig...) 放入 map,
// map 里面的--key:当前线程threadLocal value:要存放的数据
// 从这个源码我们可以看出,一个threadLocal只能关联一个数据,如果再set(),就会替换
if (map != null)
map.set(this, value);
else
//4. 如果 map 为null,就创建一个和当前线程关联的ThreadLocalMap,并且将该数据放入
createMap(t, value);
}
*/
threadLocal1.set(dog);
//threadLocal1.set(pig); //这里会替换dog
threadLocal2.set(pig); //这个数据会和 threadLocal2 关联,并且被当前线程Thread管理
String name = Thread.currentThread().getName();
System.out.println("在 Task 的 run()方法中 线程= " + name);
new T1Service().update();
}
}
public static void main(String[] args) {
new Thread(new Task()).start();//主线程启动一个线程,注意不是主线程
}
}
- 完成测试, 检测 ThreadLocal 是否可以实现在同一个线程数据安全共享
18.3 ThreadLocal 源码解读+画图
18.4 ThreadLocal 原理分析图
- ThreadLocal 原理分析图【重点 set 和 get】
- Debug 源码图,非常重要