ThreadLocal的一点理解

来源:互联网 发布:window10 共享端口 编辑:程序博客网 时间:2024/06/14 03:17

最近在看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,该变量是存储的实体。

    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocalMap是ThreadLocal中的静态内部类,构造函数声明如下:
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);        }

从上面的代码可以看到,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 - 1);            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-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();        }

另外附线程安全的几个层次:
1. 使用无状态对象
2. 线程封闭
3. 采用同步技术
其中线程封闭又包括 ad-hoc线程封闭,栈封闭,使用ThreadLocal

原创粉丝点击