线程局部变量ThreadLocal

ThreadLocal源码注释:

此类提供线程局部变量。这些变量的不同之处在于,访问该变量时会访问独属于当前线程的局部变量表。ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段(例如,用户ID或事务ID)。

只要线程是活的,并且ThreadLocal实例是可访问的,每个线程都持有对其线程局部变量副本的隐式引用;在线程消失后,线程本地实例的所有副本都将进行垃圾收集(除非存在对这些副本的其他引用)。

线程局部变量是应用层的逻辑划分。在系统层面,进程是内存分配的最小单位,线程无独立内存。

应用示例

示例1

public class HttpContextUtil {
    private static final ThreadLocal<User> USER_THREAD_LOCAL = new ThreadLocal<>();
    public static void setLoginUser(User user) { 
        USER_THREAD_LOCAL.set (user);
    }
    public static User getLoginUser() { 
        return USER_THREAD_LOCAL.get();
    }
    public static void remove() {
        USER_THREAD_LOCAL.remove();
    }
}

示例2

package android.os;

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
    /**
     * 将当前线程初始化为循环器。
     */
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    
    /**
     * 返回与当前线程关联的Looper对象。如果调用线程与Looper没有关联,则返回null。
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /**
     * 返回与当前线程关联的消息队列。
     * 这必须从运行Looper的线程调用,否则将抛出NullPointerException。
     */
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }
}

set

将值存储到thread.threadLocals中。(thread.threadLocals可视作Map<ThreadLocal, Object>

public class ThreadLocal<T> {    
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);     //返回 t.threadLocals
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);    //t.threadLocals = new ThreadLocalMap(this, firstValu0e);
        }
    }
    ......
}

get

thread.threadLocals中取出值。(thread.threadLocals可视作Map<ThreadLocal, Object>

public class ThreadLocal<T> {  
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);     //返回 t.threadLocals
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();   //map.set(this, null);
    }
}

remove

public class ThreadLocal<T> {  
    public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null) {
             m.remove(this);
         }
     }
}

ThreadLocalMap.Entry

entry对threadLocal是弱引用,对value是强引用。

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

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

总结

  • 每个Thread实例持有一个map,用来保存线程局部变量;(类似Map<ThreadLocal, Object>
  • ThreadLocal实例作为key使用,在调用过该threadLocal的线程存有对应的value,没调用过的线程没有。
  • ThreadThreadLocal 是多对多的关系(m-n)。

参考

ThreadLocal 源码解析及实战应用

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容