找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

322

积分

0

好友

40

主题
发表于 14 小时前 | 查看: 2| 回复: 0

ThreadLocal源码解析与在Android Looper中的实战应用 - 图片 - 1

多线程编程中,保证数据的一致性和操作的原子性是核心挑战。传统方式如synchronizedLock通过同步锁来确保线程安全,但锁竞争会带来线程等待,影响性能。ThreadLocal类提供了一种不同的思路:它为每个线程创建变量的独立副本,从根本上避免了共享资源引发的线程安全问题。本文将深入剖析ThreadLocal的源码实现,并探讨其在Android Looper中的经典应用。

ThreadLocal的核心概念

通俗地讲,ThreadLocal可以看作一个以线程(Thread)为键的映射表。它是一个用于创建线程局部变量的类。每个线程访问ThreadLocal变量时,都会获取到只属于当前线程的初始化副本,从而实现了线程间的数据隔离。

深入ThreadLocal源码

ThreadLocal的核心功能围绕setgetsetInitialValue这几个方法展开,它们共同协作管理线程本地变量。

/**
 * 用于设置初始值。如果用户覆盖了set()方法,则使用此方法代替set()。
 */
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;
}

/**
 * 设置当前线程中此线程局部变量的副本为指定值。
 */
public void set(T value) {
    // 1. 获取当前线程
    Thread t = Thread.currentThread();
    // 2. 获取当前线程关联的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    // 3. 如果map已存在,则以当前ThreadLocal实例为键存储值
    if (map != null)
        map.set(this, value);
    else
        // 4. 否则为当前线程创建新的ThreadLocalMap
        createMap(t, value);
}

/**
 * 返回当前线程中此线程局部变量的副本值。
 */
public T get() {
    // 1. 获取当前线程
    Thread t = Thread.currentThread();
    // 2. 获取当前线程关联的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    // 3. 如果map存在且包含对应条目,则返回值
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    // 4. 否则,进行初始化并返回初始值
    return setInitialValue();
}

/**
 * 获取与ThreadLocal关联的Map。
 */
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

/**
 * 创建与ThreadLocal关联的Map。
 */
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocal源码解析与在Android Looper中的实战应用 - 图片 - 2 ThreadLocal源码解析与在Android Looper中的实战应用 - 图片 - 3 ThreadLocal源码解析与在Android Looper中的实战应用 - 图片 - 4

(上图图示了ThreadThreadLocalThreadLocalMap三者之间的关系)

ThreadLocalMap 内部类

ThreadLocalMapThreadLocal的静态内部类,一个定制化的哈希表,专门用于维护线程本地变量。其条目Entry继承自WeakReference<ThreadLocal<?>>,使用弱引用来持有ThreadLocal键,有助于处理大范围和长生命周期的使用场景,防止内存泄漏。

static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }

    // ... 其他字段和方法

    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);
    }
}

ThreadLocal在Android Looper中的应用

Android消息机制中,Looper是每个线程进行消息循环的核心。为了确保每个线程拥有自己独立的Looper实例,系统巧妙地使用了ThreadLocal

Looper类中,通过一个静态的final变量来持有ThreadLocal实例,这保证了所有线程访问的是同一个ThreadLocal对象,但通过它获取到的Looper却是线程本地的。

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

以下是Looper类中关键方法的实现:

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    /** 初始化当前线程为一个Looper线程。 */
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        // 确保一个线程只能创建一个Looper
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 将新创建的Looper实例存入当前线程的ThreadLocalMap
        sThreadLocal.set(new Looper(quitAllowed));
    }

    /** 返回与当前线程关联的Looper对象。 */
    public static @Nullable Looper myLooper() {
        // 从当前线程的ThreadLocalMap中获取Looper
        return sThreadLocal.get();
    }
}

通过sThreadLocal.set(new Looper(quitAllowed)),每个线程都将自己唯一的Looper对象存储在了自己的ThreadLocalMap中。当需要获取当前线程的Looper时(例如在Handler构造函数中),调用Looper.myLooper(),它内部通过sThreadLocal.get()便能准确无误地取回属于当前线程的那个Looper实例。这是ThreadLocalAndroid框架中一个非常经典和高效的应用。




上一篇:Go后端开发实战:使用Argon2id算法实现安全密码存储与验证
下一篇:UART与COM接口深度解析:嵌入式开发中的硬件接口与TTL/RS-232电平标准
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 17:25 , Processed in 0.204051 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表