lol走砍e源码_从源码的角度分析Android中的线程通信

本文从源码角度深入探讨Android中线程通信,重点分析ThreadLocal如何实现数据隔离,以及Handler消息机制。首先解释ThreadLocal的工作原理,通过get()和set()方法追踪源码,揭示每个线程拥有独立的ThreadLocalMap实现数据隔离。接着,分析App启动时Looper和MessageQueue的创建,说明主线程中的Looper和MessageQueue如何通过ThreadLocal维持。最后,阐述Handler发送消息的流程,理解如何通过Handler将消息从子线程传递到主线程。
摘要由CSDN通过智能技术生成
准备知识:ThreadLocal

首先要搞清楚ThreadLocal的作用是什么,然后再去看它的源码。ThreadLocal的作用是为了实现线程间的数据隔离。(分析源码就要分析为什么ThreadLocal能做到数据隔离,以及,它在Handler中起了什么作用?)

第一个问题:ThreadLocal是如何做到数据隔离的?

要搞清楚这个问题,首先我们追踪源码,看一下,ThreadLocal是怎么放置和取出数据的。

1.1 从ThreadLocal中取数据:get()

 public T get() {
            //拿到当前线程         Thread t = Thread.currentThread();        //拿到当前线程中的 ThreadLocalMap        ThreadLocalMap map = getMap(t);        //通过下面两步,追踪可以看到,map此时为空。        if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);            if (e != null) {
                    @SuppressWarnings("unchecked")                T result = (T)e.value;                return result;            }        }        return setInitialValue();    }

点击进入源码发现这个方法首先是获取到当前的线程,然后拿到当前线程中的ThreadLocalMap。我们追踪其中的getMap(t):

    ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;    }

返回的是threadLocals,这是Thread类中的一个全局变量。追踪进去可以看到: Thread.java

 ThreadLocal.ThreadLocalMap threadLocals = null;  threadLocals = null;

在Thread.java中,对这个全局变量的定义均为null。因此在get()中,map为空,会走到setInitialValue()中。我们继续追踪到setInitialValue()中。看看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;    }

首先调用初始化方法initialValue(),得到value,如果用户重写了initialValue(),那么获得到就是用户定义的返回值。再往下走,得到的Map仍然是null,因此会走到createMap(t, value)中。继续追踪下去,看看createMap()是怎么实现的。

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

在这个方法中,定义了threadLocals这个变量。创建了ThreadLocalMap。

1.2 往ThreadLocal中添加数据。set()
   public void set(T value) {
            Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }

仍然是这样:首先获取当前线程,再通过当前线程获取到 ThreadLocalMap,在之前通过对getMap(t)的分析可以知道,此时的map = null,因此set(t)最终也会走 createMap(t, value)。之前对 createMap(t, value)的源码进行分析过, createMap(t, value)会创建一个ThreadLocalMap,并将value放入ThreadLocalMap中。

看到这里,我们发现,ThreadLocal取数据和拿数据,都是通过一个叫做ThreadLocalMap的类,那么这个类到底是个啥呢?阅读源码发现,ThreadLocalMap是ThreadLocal中的一个静态内部类:

 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> {
                /** 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.         */        private Entry[] table;      .......

这个静态内部类中,还有一个静态内部类,这个类叫做Entry,这个类比较简单,它其中维护了两个变量,分别是ThreadLocal类型的Key和Object类型的Value。在每个ThreadLocalMap中都有一个Entry类型的数组Entry[],用来存储数据。

源码阅读到这里,再结合到上面分析的ThreadLocal源码中set()的实现:

 if (map != null) map.set(this, value);

这里的Map指的是ThreadLocalMap,追踪到ThreadLocalMap中的set()

 /**         * Set the value associated with key.         *         * @param key the thread local object         * @param value the value to be set         */        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;            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) {
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值