java.lang.ThreadLocal
ThreadLocalMap
static class ThreadLocalMap {
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16;
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY]; // 数组长度16
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); // 确定index, 确定数组中的位置
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);// 当数组负载达到了,就得触发扩容。
}
Entry
// Note that null keys (i.e. entry.get() == null) mean that the key is no longer referenced, so the entry can be expunged from table.
//当key==null, 则直接删除key对象; 这就是为啥要继承WeakReference的原因了。
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k); // key作为weakReference对象的referent字段, 当key代表的threadLocal对象删除了强引用, 则在下一次gc回收的时候,就会回收掉referent, 即回收掉threadlocal对象。
//而entry对象作为reference对象本身, 当删除掉强引用后,就会被gc回收。
value = v;
}
}
ThreadLocal
/**
* The next hash code to be given out. Updated atomically. Starts at
* zero.
*/
private static AtomicInteger nextHashCode =
new AtomicInteger();
/**
* The difference between successively generated hash codes - turns
* implicit sequential thread-local IDs into near-optimally spread
* multiplicative hash values for power-of-two-sized tables.
*/
// 0110 0001 1100 1000 1000 0110 0100 0111
private static final int HASH_INCREMENT = 0x61c88647;
/**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
hashCode
如何避免或者减少碰撞呢?
如果碰撞了怎么办?
set
private void set(ThreadLocal<?> key, Object value) {
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)]) { // 旧的entry替换新值
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); // 插入新entry
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold) // 数组扩容
rehash();
}
Thread
ThreadLocal.ThreadLocalMap threadLocals = null;
- ThreadLocal.createMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); // key=threadLocal
}
- ThreadLocal.get
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //取出caller线程的threadLocals字段
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); // 根据caller ThreadLocal 对象作为key, 查找value值
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocal、ThreadLocalMap、 Thread三者之间的关系
- Thread维护一个ThreadLocalMap类型的字段
ThreadLocal.ThreadLocalMap threadLocals = null;
- ThreadLocalMap以Entry类型作为节点
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k); // threadLocal对象
value = v; // 值
}
}
单个Thread实例可以保存多个threadlocal实例及value
- ThreadLocal是工具、标识符 ThreadLocal.get 根据caller线程和 ThreadLocal对象找到value。
一个ThreadLocal实例作为多个Entry实例的key, 这多个Entry实例分别保存在多个Thread的threadLocals字段中。
也就是说线程内部的value数据, 线程实例自己保存在threadLocals字段中。
threadlocal对象,仅仅作为一个标识符和获取工具。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //取出caller线程的threadLocals字段
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); // 根据caller ThreadLocal 对象作为key, 查找value值
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}