ThreadLocal源码分析(简单)

ThreadLocal的三个常用接口set(T value)、get()、remove();

set:

public void set(T value) {
    Thread t = Thread.currentThread();
	//这个代码不用看,就是返回thread的一个属性threadLocals
    ThreadLocalMap map = getMap(t);
    if (map != null)
		//增加
        map.set(this, value);
    else
		//新建
        createMap(t, value);
}

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

	ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
		//建一个16长度的数组
        table = new Entry[INITIAL_CAPACITY];
		//对threadLocalHashCode求INITIAL_CAPACITY的余数,平时
        int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
		//Entry是弱应用,在这不展开
        table[i] = new Entry(firstKey, firstValue);
		//设置size长度
        size = 1;
		//只是设置threshold的值
        setThreshold(INITIAL_CAPACITY);
    }

	//WeakReference,弱引用
	static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
	
	private void setThreshold(int len) {
        threshold = len * 2 / 3;
    }
	
	//增加
    private void set(ThreadLocal<?> key, Object value) {

        Entry[] tab = table;
        int len = tab.length;
		//拿到现在数组的下标i
        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) {
				//找到相同的key,就结束
                e.value = value;
                return;
            }

            if (k == null) {
				//找到k是空的,占用
                replaceStaleEntry(key, value, i);
                return;
            }
        }
		//找到数组的空位,插入
        tab[i] = new Entry(key, value);
        int sz = ++size;
        if (!cleanSomeSlots(i, sz) && sz >= threshold)
			//当数值不够长时,扩容(threshold的作用体现了)
            rehash();
    }

threadLocalHashCode的获取挺特别

//简单来说threadLocalHashCode的值要最大可能性保证减少取余后的冲突
private final int threadLocalHashCode = nextHashCode();

//HASH_INCREMENT = 0x61c88647,这个魔数的作用就是让计算出来的数尽可能的散列
private static int nextHashCode() {
    return nextHashCode.getAndAdd(HASH_INCREMENT);
}

public final int getAndAdd(int delta) {
    return unsafe.getAndAddInt(this, valueOffset, delta);
}

get()

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
	//没有返回是,返回默认值
    return setInitialValue();
}

	//根据key 返回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);
    }

remove()

 public void remove() {
     ThreadLocalMap m = getMap(Thread.currentThread());
     if (m != null)
         m.remove(this);
 }

	//移除key
    private void remove(ThreadLocal<?> key) {
        Entry[] tab = table;
        int len = tab.length;
        int i = key.threadLocalHashCode & (len-1);
		//数据不一定在i位置,所以要一步一步查
        for (Entry e = tab[i];
             e != null;
             e = tab[i = nextIndex(i, len)]) {
            if (e.get() == key) {
                e.clear();
                expungeStaleEntry(i);
                return;
            }
        }
    }

通过上面的代码,很明显的一点,如何减少冲突显得很重要,所以HASH_INCREMENT = 0x61c88647很重要,
下面,我会专门写一篇文章来说明0x61c88647的由来
ThreadLocal中魔数0x61c88647如何得到

发布了148 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_33321609/article/details/104479517