ThreadLocal原理与应用详解(2)
来源:互联网 发布:福建网络安全教育 编辑:程序博客网 时间:2024/06/06 04:15
2.ThreadLocal实现原理
本文分析源代码基于Android6.0。
代码路径:
libcore/luni/src/main/java/java/lang/ThreadLocal.java
libcore/libart/src/main/java/java/lang/Thread.java
从API官方文档看,ThreadLocal提供了这样一些接口:
public:set()/get()/remove()
protected:initialValue()
从这几个API入手看一下ThreadLocal源代码。
ThreadLocal.java:
/** * Sets the value of this variable for the current thread. If set to * {@code null}, the value will be set to null and the underlying entry will * still be present. * * @param value the new value of the variable for the caller thread. */ public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); } /** * Returns the value of this variable for the current thread. If an entry * doesn't yet exist for this variable on this thread, this method will * create an entry, populating the value with the result of * {@link #initialValue()}. * * @return the current value of the variable for the calling thread. */ @SuppressWarnings("unchecked") public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); } /** * Removes the entry for this variable in the current thread. If this call * is followed by a {@link #get()} before a {@link #set}, * {@code #get()} will call {@link #initialValue()} and create a new * entry with the resulting value. * * @since 1.5 */ public void remove() { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { values.remove(this); } }
梳理一下整个逻辑:
set()/get()/remove(),从当前线程拿到其Values成员变量。Values是定义在ThreadLocal内部的一个包级可见的内部类,是一个类似Map的数据结构,实现从ThreadLocal(作为Key)到Object(作为Value)的映射。在Thread中,只定义了这样一个包级可见的成员变量,没有任何的维护逻辑,维护逻辑都在ThreadLocal中。
上面是大概框架,下面从一些点来仔细研究其实现机制。
2.1ThreadLocal对于Thread.localValues的维护
ThreadLocal得到当前线程的Values方法如下:
/** * Gets Values instance for this thread and variable type. */ Values values(Thread current) { return current.localValues; }
Thread.java:
/** * Normal thread local values. */ ThreadLocal.Values localValues;
在Thread中,只定义了这样一个包级可见的成员变量,没有任何的维护逻辑,维护逻辑都在ThreadLocal中。
(1)初始化
values()方法获取到localValues的引用,如果发现尚为null,通过initializeValues()初始化
/** * Creates Values instance for this thread and variable type. */ Values initializeValues(Thread current) { return current.localValues = new Values(); }
接下来看看Values类的构造方法
/** * Constructs a new, empty instance. */ Values() { initializeTable(INITIAL_SIZE); this.size = 0; this.tombstones = 0; } /** * Used for InheritableThreadLocals. */ Values(Values fromParent) { this.table = fromParent.table.clone(); this.mask = fromParent.mask; this.size = fromParent.size; this.tombstones = fromParent.tombstones; this.maximumLoad = fromParent.maximumLoad; this.clean = fromParent.clean; inheritValues(fromParent); }
前者比较简单。后者是从一个Parent Values对象创建一个新的Values对象,应用于InheritableThreadLocal。继承稍后介绍。
(2)继承
InheritableThreadLocal是ThreadLocal的一个子类,这里不扩展介绍。继续看看Values的inheritValues()方法
/** * Inherits values from a parent thread. */ @SuppressWarnings({"unchecked"}) private void inheritValues(Values fromParent) { // Transfer values from parent to child thread. Object[] table = this.table; for (int i = table.length - 2; i >= 0; i -= 2) { Object k = table[i]; if (k == null || k == TOMBSTONE) { // Skip this entry. continue; } // The table can only contain null, tombstones and references. Reference<InheritableThreadLocal<?>> reference = (Reference<InheritableThreadLocal<?>>) k; // Raw type enables us to pass in an Object below. InheritableThreadLocal key = reference.get(); if (key != null) { // Replace value with filtered value. // We should just let exceptions bubble out and tank // the thread creation table[i + 1] = key.childValue(fromParent.table[i + 1]); } else { // The key was reclaimed. table[i] = TOMBSTONE; table[i + 1] = null; fromParent.table[i] = TOMBSTONE; fromParent.table[i + 1] = null; tombstones++; fromParent.tombstones++; size--; fromParent.size--; } } }
这个方法的作用即从父Thread继承线程本地变量值。
- ThreadLocal原理与应用详解(2)
- ThreadLocal原理与应用详解(1)
- ThreadLocal原理与应用
- ThreadLocal原理与应用
- Java解读-ThreadLocal详解与应用
- threadlocal原理及常用应用场景2
- ThreadLocal原理及应用
- ThreadLocal原理详解
- J.U.C--ThreadLocal的应用与使用原理
- J.U.C--ThreadLocal的应用与使用原理
- ThreadLocal的底层实现原理与应用场景
- ThreadLocal原理与用法
- threadLocal 原理与使用
- ThreadLocal原理及其实际应用
- ThreadLocal原理及其实际应用
- ThreadLocal原理及其实际应用
- ThreadLocal原理及其实际应用
- ThreadLocal 的应用及原理
- Laravel 数据库加密及数据库表前缀配置
- 【牛客 题库】 指针移动 || 类创建对象的个数|| 求字符串数组中长度最短的字符串所在的行下标
- JQuery 里面的 click 事件会累加
- 修改Nginx网站根目录
- Gradle 安装
- ThreadLocal原理与应用详解(2)
- 中断线程化的注册
- 2.1 借助 Intent 让 Activity 拿着数据瞬间移动
- 初探Promise
- 【Docker】Dockerfile指令
- 检索的页面的虚拟空间信息
- 线程池shutdown初认识
- Good Bye.
- 全面理解Java内存模型