1.对ThreadLocal的理解
ThreadLocal是一个创建线程局部量的类。使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。
2.主要方法的分析
2.1 set()
//set值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//getMap()函数
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
set的过程可以分为3个过程:
1.获取当前的线程
2.获取线程里面的ThreadLocal.ThreadLocalMap
3.看这个ThreadLocal.ThreadLocalMap是否存在,存在就设置一个值,不存在就给线程创建一个ThreadLocal.ThreaLocalMap
第三点有两个分支,如下:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//
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);
}
//
private final int threadLocalHashCode = nextHashCode();
//
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
//
private static AtomicInteger nextHashCode =
new AtomicInteger();
这个Map中并没有next节点,所以他的存储方式不是链表的形式。
下面看一下其创建分支:
private void set(ThreadLocal key, Object value) {
// We don't use a fast path as with get() because 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;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
上面代码的大致逻辑可以分为:
1.先对ThreadLocal里面的threadLocalHashCode取模获取到一个table的位置。
2.如果这个位置有数据,获取这个位置上的ThreaLocal
(1)判断一下位置上的ThreadLocal和本身这个是不是一个ThreadLocal,是的话数据就覆盖。
(2)如果不是同一个ThreadLocal,就判断一下这个位置上的Threadlocal是否为空,返回。
2.2 get()
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
//获取Entry
private Entry getEntry(ThreadLocal key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
//获取失败后的处理
private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal k = e.get();
if (k == key)
return e;
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
概括一下上面的逻辑:
1.获取当前线程
2.去当前线程中得到ThreadLocal.ThreadLocalMap
3.当前线程中判断是否有ThreadLocal.ThreadLocalMap
(1)有就尝试根据当前ThreadLocal的ThreadLocalHashCode取模取table的值,有就返回,没有就+1继续找。
(2)没有就调用set方法给当前线程ThreadLocal.ThreadLocalMap设置一个初始值。
2.3remove()
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
取得当前线程的ThreadLocal.ThreadLocalMap,如果有ThreadLocal.ThreadLocalMap,找到对应的Entry,移除就可以了。
网友评论