ThreadLocal类源码解析
来源:互联网 发布:疯狂联盟座狼升级数据 编辑:程序博客网 时间:2024/05/18 02:25
一、什么是ThreadLocal
该类提供了线程局部 (thread-local) 变量。这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
例如,以下类生成对每个线程唯一的局部标识符。线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。
import java.util.concurrent.atomic.AtomicInteger; public class UniqueThreadIdGenerator { private static final AtomicInteger uniqueId = new AtomicInteger(0); private static final ThreadLocal < Integer > uniqueNum = new ThreadLocal < Integer > () { @Override protected Integer initialValue() { return uniqueId.getAndIncrement(); } }; public static int getCurrentThreadId() { return uniqueId.get(); } } // UniqueThreadIdGenerator
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
二、ThreadLocal 的实现原理
每个ThreadLocal类创建一个Map,然后用线程的ID作为Map的key,实例对象作为Map的value,这样就能达到各个线程的值隔离的效果。为了实现该设计思想,在ThreadLocal类有以下方法
下面我们实现原理的源码解析:
protected T initialValue() { return null; }
该方法返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。
该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。
/** * 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) return (T)e.value; } return setInitialValue(); }
该方法返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用 initialValue() 方法返回的值。
/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
该方法将此线程局部变量的当前线程副本中的值设置为指定值。大部分子类不需要重写此方法,它们只依靠 initialValue() 方法来设置线程局部变量的值。
/** * Removes the current thread's value for this thread-local * variable. If this thread-local variable is subsequently * {@linkplain #get read} by the current thread, its value will be * reinitialized by invoking its {@link #initialValue} method, * unless its value is {@linkplain #set set} by the current thread * in the interim. This may result in multiple invocations of the * <tt>initialValue</tt> method in the current thread. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
该方法主要用于移除此线程局部变量当前线程的值。
在上面的方法中我们注意到其使用了一个ThreadLocalMap 类 ,其是如何设计的呢?
在ThreadLocal 中提供了一个静态内部类 ThreadLocalMap。每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,value是真正需要存储的Object。当Thread销毁之后对应的ThreadLocalMap也就随之销毁了,能减少内存使用量。
观察源码可以看到如下:
static class ThreadLocalMap { //ThreadLocal类中的getMap 和creatMap方法 ThreadLocalMap getMap(Thread t) { return t.threadLocals; } /** * 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 * @param map the map to store. */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } }
- ThreadLocal类源码解析
- JDK源码解析之ThreadLocal类
- JDK源码解析之ThreadLocal类
- ThreadLocal类的用法与源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析
- threadlocal源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析(二)
- ThreadLocal源码解析
- ThreadLocal 源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析
- ThreadLocal源码解析
- lightoj 1198 - Karate Competition 【贪心】
- IOS App常用界面结构解析,让开发更简单
- SAR成像学习(三)距离方向成像matlab代码解析 1
- 四 单例模式
- leetcode刷题8. String to Integer (atoi)
- ThreadLocal类源码解析
- java---序列六(合并流)SequenceInputStream ——对多个流进行合并
- 致自己
- 开发工具
- js中call与apply用法
- 深入理解JVM(九)——类加载的过程
- leetcode 93. Restore IP Addresses
- lightoj 1328 - A Gift from the Setter 【数学】
- 欢迎使用CSDN-markdown编辑器