ThreadLocal的理解

ThreadLocal的理解

以前了解过threadLocal,只是知道它可以让开发者在不同的线程中对同一个对象做备份,但是从来没有使用过,理解的也不是很深,接下来准备研究下android Handler的源码,发现网上的博客有的先介绍了ThreadLocal,看了一会就自己去看源代码了,我认为看源代码虽然慢,但是会让人理解的透彻,所以看博客的正确打开方式是:看别人的总结和分析(毕竟是巨人的肩膀),然后自己再看源代码撸一遍,这样会有自己的理解。好了,开始分析源码吧。

首先看ThreadLocal这个类。

/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.  {@code ThreadLocal} instances are typically private
 * static fields in classes that wish to associate state with a thread (e.g.,
 * a user ID or Transaction ID).**/
public class ThreadLocal<T> {

   public T get() {
        Thread t = Thread.currentThread();
		//获取每个线程中的变量ThreadLocal.ThreadLocalMap threadLocals
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        //获取该线程中该ThreadLocal对象对应的Entry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                //取值
                T result = (T)e.value;
                return result;
            }
        }
        //没有改ThreadLocal对象对用的entry
        return setInitialValue();
    }
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
	//默认返回Null
      protected T initialValue() {
        return null;
    }

	public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
}

ThreadLocal,T是一个泛型,泛型的本质是参数的传递,这一点从get的返回值和set的参数中可以看出。ThreadLocal主要有俩个方法,get和set,先分析get,getMap返回thread类的一个变量ThreadLocal.ThreadLocalMap threadLocals,那ThreadLocalMap是什么,查看源码。

static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  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.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
		//可以看到,Entry是继承自WeakReference,也就是说,每一个Entry是通过弱引用指向的ThreadLocal,这样做的好处是,即使线程还存在,如果这个ThreadLocal的强引用不在了,那么即使其他线程还引用这个ThreadLocal,这个ThreadLocal也可以伴随java的垃圾回收机制而销毁。
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
		//重点,ThreadLocalMap维护了一个Entry数组,这个数组中每一个Entry由持有某一个ThreadLocal对象的弱引用以及该ThreadLocal对应的Object value;
        private Entry[] table;

        private Entry getEntry(ThreadLocal<?> key) {
        //通过该ThreadLocal对象,运用某种算法计算数组的索引,
            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);
        }
		
		//重点
		 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;
            //通过该ThreadLocal对象,运用某种算法计算数组的索引,int i = key.threadLocalHashCode & (len-1);
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
				//如果索引到的数组位置的key相等,将value设置进去。
                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
			//如果没有,就将该ThreadLocal对象和value封装成Entry放入数组。
            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
        }
      

通过源码可以画一张图,大概是这样:
在这里插入图片描述
为什么是threadLocal对象,我想正是通过这样的设计,让每个线程都维护一个同一个对象对应不同变量的数组,然后通过泛型限制下只能是threadLocal对象,然后对外抛出了这个能力供开发者使用。记录下看到的源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值