最近在看Spring,了解到spring中绝大部分的bean都可以声明为singleton的,是因为spring对bean中的一些非线程安全的状态采用ThreadLocal来处理,让他们变成了线程安全的bean。例如在TranscationSynchronizationManaer中:
public abstract class TranscationSynchronizationManager{
//用于保存每个事务线程对应的connection或者session等资源
private static final ThreadLocal resources = new ThreadLocal();
//用于保存每个事务线程对应事务的名称
private static final ThreadLocal currentTranscationName = new ThreadLocal();
//用于保存每个事务线程对应事务的read-only状态
private static final ThreadLocal currentTranscationReadOnly = new ThreadLocal();
.....
}
ThreadLocal 是如何存储变量的呢?首先在Thread类中有一个变量threadLocals,类型为ThreadLocal中的静态内部类ThreadLocalMap,该变量是存储的实体。
ThreadLocalMap是ThreadLocal中的静态内部类,构造函数声明如下:
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - );
table[i] = new Entry(firstKey, firstValue);
size = ;
setThreshold(INITIAL_CAPACITY);
}
从上面的代码可以看到,ThreadLocalMap有点类似于HashMap的存储。键为TheadLocal类型的变量,值为所要存储的与该ThreadLocal类型的变量的绑定值。table是一个数组,存储的变量类型为Entry,但是Entry中并没有定义用于解决hash冲突的next指针,这里采用的是线性探测再散列的方法解决冲突。
然后,就可以在ThreadLocal中可以调用get()方法来获取指定的值。
//ThreadLocal中的方法
public T get() {
Thread t = Thread.currentThread();//获取到当前的线程
ThreadLocalMap map = getMap(t);//获取到当前线程对象中存储的ThreadLocalMap变量
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//键为当前的ThreadLocal对象
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
//THreadLocalMap中的方法
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - );
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);//这里就是尝试寻找下一个位置的元素
}
如果要往ThreadLocalMap中插入值
public void set(T value) {//THreadLocal中的方法
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);//获取当前线程对象中存储的ThreadLocalMap对象
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//ThreadLocalMap中的变量
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-);
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();
}
另外附线程安全的几个层次:
1. 使用无状态对象
2. 线程封闭
3. 采用同步技术
其中线程封闭又包括 ad-hoc线程封闭,栈封闭,使用ThreadLocal