ThreadLocal,线程本地化对象,在多线程环境中,使用ThreadLocal对象来维护变量时,ThreadLocal为每个使用该变量的线程维护一个独立的线程副本。
ThreadLocal.java源文件内容为:
/** * ThreadLocal内部包含一个用数组实现的哈希表,用来存储对应到每个线程的局部对象的值 * 其中,ThreadLocal对象担当key,实际通过threadLocalHashCode值来进行检索 */ public class ThreadLocal<T> { //其中 T 类型代表的是被多个线程访问的局部变量类型 /** * 在ThreadLocalMaps中用于产生哈希值 */ private final int threadLocalHashCode = nextHashCode(); /** * Returns the current thread's "initial value" for this * thread-local variable. This method will be invoked the first * time a thread accesses the variable with the {@link #get} * method, unless the thread previously invoked the {@link #set} * method, in which case the <tt>initialValue</tt> method will not * be invoked for the thread. Normally, this method is invoked at * most once per thread, but it may be invoked again in case of * subsequent invocations of {@link #remove} followed by {@link #get}. * * <p>This implementation simply returns <tt>null</tt>; if the * programmer desires thread-local variables to have an initial * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be * subclassed, and this method overridden. Typically, an * anonymous inner class will be used. * * @return the initial value for this thread-local(返回当前线程局部对象的初始值) */ protected T initialValue() { //protected成员,期望被子类继承 return null; } /** * 返回在当前线程中的线程局部对象的值, * 若线程局部对象对于当前线程没有值,则被初始化微 initialValue方法的返回值 */ 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(); } /** * 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 method to set the values of thread-locals. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) //以当前线程对象为key,设置当前局部对象的值 map.set(this, value); else createMap(t, value); } /** * 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. */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) //从ThreadLocalMap中移除对象 m.remove(this); } /** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { //返回当前Threadlocal相关的ThreadLocalMap对象 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); //为当前线程创建关联的ThreadLocalMap对象 } //ThreadLocalMap是一个定制的只能用来存储线程局部对象的哈希映射 //使用弱引用来当做key,只有当表空间不够时,旧的对象才会被移除 static class ThreadLocalMap { //ThreadLocalMap的内部数组的元素类型:使用对ThreadLocal的弱引用类型来作为元素类型 static class Entry extends WeakReference<ThreadLocal> { /** * The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } } //哈希表的初始大小 private static final int INITIAL_CAPACITY = 16; /** * 用于存储ThreadLocal弱引用的数组 */ private Entry[] table; //ThreadLocalMap使用延迟初始化,当我们需要向ThreadLocalMap中放元素时,才会初始化它 ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); //初始时,使用ThreadLocal.threadLocalHashCode作为哈希表的哈希值 size = 1; //设定ThreadLocalMap中元素个数 setThreshold(INITIAL_CAPACITY); } /** * 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) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } /** * Remove the entry for key. */ private void remove(ThreadLocal key) { 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)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } } }
ThreadLocal使用一个ThreadLocalMap对象(内部通过数组和哈希来保存,以当前线程为键)来为每一个线程保存一份变量的本地化对象。
相关推荐
主要给大家介绍了关于Java并发编程学习之源码分析ThreadLocal的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
jdk源码学习 JavaSourceLearn 版本号 版本 corretto-1.8.0_275 方式 逐步阅读源码添加注释、notes文件夹添加笔记 计划学习任务计划 标题为包名,后面序号为优先级1-4,优先级递减 java.lang Object 1 String 1 ...
ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,特别适用于各个线程依赖不通的变量值完成操作的场景。下面我们来详细了解一下它吧
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...
3、ThreadLocal 的底层实现与使用 4、ReentrantLock底层实现和如何使用 5、Condition源码分析 6、ReentrantReadWriteLock底层实现原理 7、并发工具类CountDownLatch 、CyclicBarrier和Semaphore底层实现原理 8、...
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...
使用 ThreadLocal 保存用户状态,通过拦截器拦截请求,根据自定义注解判断用户登录状态 使用 Ajax 异步发帖、发送私信、评论 使用 Redis 实现点赞、关注功能,优化登录模块——存储登录凭证、缓存用户信息 【备注】 ...
源码 设计模式 java 并发 public class Foo { // SimpleDateFormat is not thread-safe, so give one to each thread private static final ThreadLocal formatter = new ThreadLocal(){ @Override protected ...
1.1、概述 1.2、原理 1.3、值得注意 2.1 ThreadLocal使用场景 2.2、深入源码查看实现原理
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...
了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很多博文有关于对flask上下文管理的...
百度地图开发java源码 MD-Notes:后端笔记总结 关于 MD-Notes: 业余时间学习技术的同时,做一些记录和总结并乐于分享。 日常主要接触 Web 前后端开发、Linux 运维等,有 Java / Python 后端经验,有大数据开发 ...
第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...
第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...
第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...
第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...