「这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战」
一、ThreadLocal的介绍
ThreadLocal并不是一个Thread,而是Thread的局部变量。ThreadLocal为每个线程都创建了一个副本,不会出现一个线程读取变量时而被另一个线程修改的现象,它为解决多线程程序的并发问题提供了一种新的思路
一、ThreadLocal、volatile 和 synchronized的区别
- volatile只能确保操作的是同一块内存,并不能保证操作的原子性。所以volatile一般用于声明简单类型变量,使得这些变量具有原子性,即一些简单的赋值与返回操作将被确保不中断。但是当该变量的值由自身的上一个决定时,volatile的作用就将失效,这是由volatile关键字的性质所决定的。
- ThreadLocal和Synchonized都用于解决多线程并发访问
- synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问,它用于在多个线程间通信时能够获得数据共享
- ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享
- Synchronized是为了让多线程进行数据共享,而ThreadLocal为了让多线程进行数据隔离
一、ThreadLocal源码分析
- get(): 首先取得当前线程,再通过getMap(t)方法获取到一个ThreadLocalMap类型的map,接着调用getEntry(this)获取到<key,value>键值对(这里获取键值对传进去的是 this,而不是当前线程t)。如果获取成功,则返回value值;如果map为空,则调用setInitialValue方法返回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();
}
- set(T value) ThreadLocalMap 为 ThreadLocal 的一个静态内部类,里面定义了Entry 来保存数据。而且是继承的弱引用。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value。对于每个线程内部有个ThreadLocal.ThreadLocalMap 变量,存取值的时候,也是从这个容器中来获取
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
初始化该线程对象的map变量,其中key 为当前的threadlocal 变量
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
}