该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
一、ThreadLocal简单使用
三个线程,线程1依次打印1、2、3、4、5......线程2依次打印1、3、5、7、9.....线程3依次打印1、2、4、8、16......
public class threadLocal {
public static void main(String[] args) {
//
final ThreadLocal<Integer> tl1=new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
//给ThreadLocal附上初始值
return 1;
}
};
new Thread(new Runnable() {
public void run() {
while (true){
Integer a=tl1.get();
System.out.println(Thread.currentThread().getName()+" "+a);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tl1.set(++a);
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
Integer b = tl1.get();
System.out.println(Thread.currentThread().getName() + " " + b);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tl1.set(b + 2);
// tl1.set(++b);
}
}
}).start();
// new Thread(new Runnable() {
// public void run() {
// while (true) {
// Integer c = tl1.get();
// System.out.println(Thread.currentThread().getName() + " " + c);
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// tl1.set(c);
// }
// }
// }).start();
}
}
为了看的直观,这里只有前两个线程执行,第三个线程数值增率太大,给注掉了
ThreadLocal类的部分源码分析:
//获取线程中值
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();
}
//初始化方法
private T setInitialValue() {
//其实等价于 value = null
T value = initialValue();
//获取当前线程
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//创建ThreadLocalMap
createMap(t, value);
return value;
}
//设置值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//创建ThreadLocalMap
createMap(t, value);
}
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
/**
* @Author Loujitao
* @Date 2018/7/24
* @Time 9:51
* @Description:
* ThreadLocalMap 是ThreadLocal的内部类,在Thread类中有引用
* 即每个Thread类,都有自己的成员变量ThreadLocalMap,不会共享;
* 而ThreadLocal是获取线程自己的ThreadLocalMap,然后往里面放值
* 所以实现了线程间的数据隔离
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
在每个Thread类里面,都有一个ThreadLocalMap的引用,不过它一直是null的。这样在不使用它的时候也不需要占用Thread的内存,当使用到ThreadLocal的时候,便将它实例化出来,用来存储线程自己的数值,保证线程间数据隔离。
取值的过程:使用时的get()方法
调用ThreadLocal里的get()方法
ThreadLocalMap里的getEntry()。
ThreadLocalMap是怎么存储值得。
好了,以上大致就是ThreadLocal的使用方式,以及为什么它是线程间数据隔离的原因了。觉得有帮助的小伙伴可以点下关注,发现有问题的博客也可以在下方评论出留言,我会验证并及时更正的。