Android消息机制分析(二)ThreadLocal

Android消息机制分析(二)ThreadLocal

概述

ThreadLocal是Java线程中的一种解决资源共享的方式,又叫线程本地存储,以根除对变量的共享来防止任务在共享资源上产生冲突。是一种自动化机制,可以为使用相同变量的每个不同的线程都创建不同的存储。其对象通常当做静态域存储,你只能通过get()set()方法访问该对象的内容。

应用场景

ThreadLocal最常应用的地方多为数据库链接、Session管理的地方,例如封装Hibernate的模板代码时就会用到,当然还有我们之前讨论的Looper中也用到了。

源码分析

从上面的概述里我们知道,ThreadLocal只能使用get()set()方法访问该对象的内容。那我们就先从get()方法看起。

/**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    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();
    }

首先拿到当前线程,再用当前线程拿到一个ThreadLoacalMap类,看一下这个类长什么样子:

 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.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        //到这里为止就是最重要的部分,后面的代码有兴趣可以自己去看

可以看到这个类主要就是有一个内部类Entry来存储键值对,键为ThreadLocal,值为Object
再来看看getMap(t)方法。

/**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

直接返回Thread的threadLocals属性,进去看一下这个属性:

/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

就是一个值为nullThreadLocaMap,但是从threadLocals这个属性的名字就可以看得出来,其中可以存储复数个Entry的键值对。继续往下看。

if (map != null) {
	ThreadLocalMap.Entry e = map.getEntry(this);//注意这里

这里使用this,就是取出键与当前ThreadLocal对应的Entry

if (e != null) {
	@SuppressWarnings("unchecked")
	T result = (T)e.value;
	return result;
}

如果取出的Entry不为空就直接返回对应的值。接下来看最后一个方法。

/**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    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;
    }

首先initialValue()初始化一个值,接下来取ThreadThreadLocalMap。如果map不为空,直接将初始化的值填进去。如果map为空,则调用createMap。不管怎样,最终都会返回初始化的值。但是这个初始化方法返回的值默认是null。所以如果不重写initialValue(),则只能先set()get(),否则会报空指针异常。

/**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

这个方法就是单纯的创建一个ThreadLocalMap

到这里,大家应该都明白ThreadLocal的大致结构了吧。

总结

  • 每个线程中都有一个ThreadLocalMap的属性threadLocals,其中可以存储复数个Entry键值对,键为ThreadLocal,值为Object,用来存储用户变量副本。
  • 如果不重写initialValue(),则只能先set()get(),否则会报空指针异常。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值