ThreadLocal
概念
ThreadLocal
叫做本地线程变量,也就是说,ThreadLocal
中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的,ThreadLocal
为变量在每个线程中创建了一个副本,这样每个线程都可以访问自己内部的副本变量。
作用
- 可以实现在同一个线程数据共享,从而解决多线程数据安全问题
- 可以通过
set
方法给当前线程关联一个数据 - 数据是以Map的形式存储的,key就是当前线程。数据的获取可以通过
get
方法 - 每一个ThreadLocal对象,只能为当前线程关联一个数据,如果想要关联多个数据,就需要使用多个ThreadLocal对象实例
- 在ThreadLocal中保存数据,在线程销毁后会自动释放
演示
Cat类
package com.threadLocal;
/**
* @author long
* @date 2022/9/15
*/
public class Cat {
}
Service类
package com.threadLocal;
/**
* @author long
* @date 2022/9/15
*/
public class Service {
public void show(){
System.out.println("Service当前线程=" + Thread.currentThread().getName());
System.out.println("Service获取的对象是" + ThreadLocalTest.threadLocal.get());
Dao dao = new Dao();
dao.show();
}
}
Dao类
package com.threadLocal;
/**
* @author long
* @date 2022/9/15
*/
public class Dao {
public void show(){
System.out.println("Dao当前线程=" + Thread.currentThread().getName());
System.out.println("Dao获取的对象是" + ThreadLocalTest.threadLocal.get());
}
}
ThreadLocalTest类
package com.threadLocal;
/**
* @author long
* @date 2022/9/15
*/
public class ThreadLocalTest {
public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();
private static class MyTest implements Runnable{
@Override
public void run() {
Cat cat = new Cat();
threadLocal.set(cat);
System.out.println("run方法设置对象为" + cat);
Service service = new Service();
service.show();
}
}
public static void main(String[] args) {
Thread thread = new Thread(new MyTest());
thread.start();
}
}
源码
ThreadLocal里边最重要的是有两个个方法
set()
public void set(T value) {
// 获取到当前线程
Thread t = Thread.currentThread();
// 根据当前线程来获取其对应的Map
ThreadLocalMap map = getMap(t);
if (map != null)
// 如果Map不为空,就将数据存放进去;这里的this是set的方法调用者(ThreadLocal对象),所以这里Map中的键值对是唯一的
map.set(this, value);
else
// 如果Map不存在,就创建一个和当前线程对应的Map
createMap(t, value);
}
get()
public T get() {
// 获取到当前线程
Thread t = Thread.currentThread();
// 根据当前线程来获取其对应的Map
ThreadLocalMap map = getMap(t);
if (map != null) {
// 如果Map不为空,就根据对应的ThreadLocal对象来获取存储的值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
// 如果Entry不为空,就获取到存储的值返回
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
- 一个ThreadLocal对象只能存储一个
k-v
。因为ThreadLocal对象调用set()的时候,是以该ThreadLocal对象作为k值存储的。 - 要想存储多个值,就得创建多个ThreadLocal对象。
底层图示
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Lunatic!
评论