更新中······
是什么
简单来说:
1、 ThreadLocal提供了一种定义线程的局部变量的方式
2、这个局部变量在多个线程中拥有不同的副本
特点:
- 简单(使用简单)
- 快速(无额外开销)
- 安全(线程安全)
初步认识:
- 构造函数ThreadLocal()
- 初始化 intialValue()
- 访问器 get()/set()
- 回收 remove()
这个类很简单,主要就这么几个方法,顾名思义,很容易看懂每个方法什么意思。
- 1、ThreadLocal提供了一种访问某个变量的特殊方式,访问到的变量属于当前线程,即保证每个线程的变量都不一样,二同一个线程在任何地方拿到的变量都是一致的,这就是所谓的线程隔离。
- 2、如果要使用ThreadLocal,通常定义为private static类型
解决什么问题
- 资源持有
- 线程一致性
- 并发计算
- 线程安全
当你想在多个方法中使用某个变量,这个变量是当前线程的状态,其他线程都不不依赖这个变量
我们通常会把这个变量定义在方法内部,然后在方法之间通过参数传递使用。
这个方法能解决问题,但是
- 每个需要用到这个变量的方法,都需要声明形参
- 如果引用的方法比较多,层次比较深,会非常影响代码的美观,并且增加维护成本。
- 而且,如果这些方法都是已定义好的,现在需要增加一个新的变量,你就需要去修改每个方法的形参,以及调用这个方法的地方。
怎么用
这时候ThreadLocal就派上用场了,请看代码:
//ThreadLocal
private static ThreadLocal<String> holder = new ThreadLocal<>();
//嵌套方法a
public void doA(){
String param = holder.get();
doB();
}
//嵌套方法b
public void doB(){
String param = holder.get();
doC();
}
//嵌套方法c
public void doC(){
String param = holder.get();
}
public static void main(String[] args) {
//绑定参数到当前线程
String name = "123";
holder.set(name);
tyr(){
doA();
}finanly{
//最后清理掉,防止内存泄漏(为什么?后面原理中有说明)
holder.clear();
}
}
如果只是想知道怎么用,看到这里就够了,如果想深入了解,请继续往下看。
原理解析
Java中使用 哈希表 实现
源码解析
首先来看看看源码
ThreadLocal中有三个方法:分别是 get() 、 set(T value) 、remove()
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();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
继承性
ThreadLocal 定义的变量不具有继承性,(父线程定义的变量,子线程中是访问不到的)
InheritableThreadLocal 顾名思义,这个类是支持子线程访问父线程定义的变量的。
请看代码:
public class Test {
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
private static InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
String mainvalue = "mainValue";
threadLocal.set(mainvalue);
inheritableThreadLocal.set(mainvalue);
//打印主线程的值
System.out.println(Thread.currentThread().getName() + "【threadLocal-父线程访问】" + threadLocal.get());
System.out.println(Thread.currentThread().getName() + "【inheritableThreadLocal-父线程访问】" + threadLocal.get());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//打印子线程的值
System.out.println(Thread.currentThread().getName() + "【threadLocal-子线程访问】:" + threadLocal.get());
System.out.println(Thread.currentThread().getName() + "【inheritableThreadLocal-子线程访问】" + inheritableThreadLocal.get());
}
});
thread.start();
}
}
控制台输出结果:
main【threadLocal-父线程访问】mainValue
main【inheritableThreadLocal-父线程访问】mainValue
Thread-0【threadLocal-子线程访问】:null
Thread-0【inheritableThreadLocal-子线程访问】mainValue
从上面的代码可以看出
- ThreadLocal父线程中绑定的变量,子线程中是获取不到的。
- InheritableThreadLocal父线程绑定的变量,子线程是可以获取到的。