线程安全大概分为两类 :
一类是多个线程共享一个变量 访问时候加锁,属于以时间换空间
一类是每个线程有自己的变量(不需要共享),不需要加锁 速度更快 但是 耗费内存 (为每个线程new了一个变量)
还有一种是使用不可变对象 要求这个对象是final类型 它的属性也是final类型并且有正确的初始化(参考Java并发实战 3.4不变性)
而ThreadLocal就属于后者
主要方法:
set(T t)
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //获取当前线程的ThreadLocalMap对象 此map属于Thread的一个属性
if (map != null)
map.set(this, value); //不为null则以当前ThreadLocal 为key 保存到当前线程的ThreadLocalMap对象里
else
createMap(t, value); //为null 则为当前线程创建ThreadLocalMap对象
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);//获取当前线程的ThreadLocalMap对象
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //以当前ThreadLocal对象获取value
if (e != null)
return (T)e.value;
}
return setInitialValue(); //初始化当前线程的ThreadLocalMap对象 以当前ThreadLocal对象为key null为value
}
主要属性
内部类 Entry 保存ThreadLocal和需要存储的变量
static class Entry extends WeakReference<ThreadLocal> {
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
private Entry[] table; //程序中有多个ThreadLocal时候,多个ThreadLocal 调用 set方法设置的变量都保存到这个table里了
主要方法:
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();
}