ThreadLocal的场景是用来隔离各个线程的局部变量,各个线程之间的数值互不干扰。
先查看个例子:
final ThreadLocal threadLocal = new ThreadLocal<>();
threadLocal.set(true);
Log.e(TAG, Thread.currentThread()+"="+threadLocal.get());
new Thread(new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread()+"="+threadLocal.get());
}
}).start();
执行的结果如下:
Thread[main,5,main]=true
Thread[Thread-5,5,main]=null
从结果看 主线程和子线程获取的threadLocal值不同,所以应用于线程数据隔离
源码查看Set(true)方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//获取线程对应的ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//ThreadLocal变量跟对象实例firstValue由线程的threadLocals来维护
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
private void set(ThreadLocal> key, Object value) {
// We don't use a fast path cas with get() beause it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table; //table是ThreadMap内的Entry数组
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); //获取hash值,用于数组中的小标
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
//如果数组中有对应的值则进入
ThreadLocal> k = e.get();
//key值相等则覆盖值
if (k == key) {
e.value = value;
return;
}
//此时说明此处 Entry 的 k 中的对象实例已经被回收了,需要替换掉这个位置的 key 和 value
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
//创建 Entry 对象
tab[i] = new Entry(key, value);
int sz = ++size;
//超过负载因子,则扩充
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
源码查看get()方法
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();
}
get()方法就是根据所在线程获取ThreadLocalMap,根据TheadLocal获取对应的ThreadLocalMap.Entry,然后获取对应的value值,否则返回setInitialValue()=null