1、源码分析

此处以JDK1.8版本分析

1.1 set方法

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

此处的ThreadLocalMap为ThreadLocal的一个内部类,用Entry来存储要设置的值。如下

   static class ThreadLocalMap {

        /**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value; Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
  }

看下getMap()方法,用于返回当前ThreadLocal维护的ThreadLocalMap对象,如下

    /**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}

此处的t.threadLocals为当前Thread维护的ThreadLocalMap对象

  /* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

再看下createMap()方法,用于为当前Thread没有ThreadLocalMap时新建一个ThreadLocalMap,如下

  /**
* 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
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}

从源码中可以看出set方法过程:获取当前线程,并作为句柄去获取ThreadLocalMap,如果ThreadLocalMap存在,则以当前ThreadLocal对象为key,传入的对象为value进行存储。否则新建一个和当前线程相关联的ThreadLocalMap来存储。

1.2 get方法

  /**
* 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) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

从源码可以看出也是以当前线程为句柄获取ThreadLocalMap对象,如果存在则返回当前线程的ThreadLocal为key对应的值,否则设置初始值setInitialValue

    /**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
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;
}

其中initialValue返回null

/**
* 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 {@code initialValue} 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 {@code null}; if the
* programmer desires thread-local variables to have an initial
* value other than {@code null}, {@code ThreadLocal} 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() {
return null;
}

1.3 remove()方法

    /**
* 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
* {@code initialValue} method in the current thread.
*
* @since 1.5
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}

从源码可以很容易看出remove的作用过程,不做详细分析。为了避免内存泄漏问题,尽量在当前线程处理完之后手动进行remove操作。

2、总结

从上面的源码可以看出ThreadLocal设置的值和线程相关,可以理解为是线程的私有的访问区域,其他线程无法访问,实现了“数据隔离”效果。和解决并发问题和共享变量无关

每个Thread都维护者一个ThreadLocalMap的引用。

java ThreadLocal使用的更多相关文章

  1. Java ThreadLocal的使用

    Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量.因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的Thread ...

  2. Java ThreadLocal 源代码分析

    Java ThreadLocal 之前在写SSM项目的时候使用过一个叫PageHelper的插件 可以自动完成分页而不用手动写SQL limit 用起来大概是这样的 最开始的时候觉得很困惑,因为直接使 ...

  3. java threadLocal的初探

    在网上找了半天,终于找到一篇靠谱的文章了. 文章地址:http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6% ...

  4. Java ThreadLocal Example(java中的ThreadLocal例子)

    Java ThreadLocal is used to create thread local variables. We know that all threads of an Object sha ...

  5. Java ThreadLocal

    ThreadLocal类,代表一个线程局部变量,通过把数据放在ThreadLocal中,可以让每个线程创建一个该变量的副本.也可以看成是线程同步的另一种方式吧,通过为每个线程创建一个变量的线程本地副本 ...

  6. 【01-14】java ThreadLocal工具类

    自定义ThreadLocal package concurrent; import java.util.HashMap; import java.util.Map; /** * @author alo ...

  7. Java ThreadLocal 理解

    ThreadLocal 概念: ThreadLocal不是用来解决对象共享访问的问题,而主要是提供了保存对象的方法和避免参数传递的方便的对象访问方式. ThreadLocal并不是一个Thread,而 ...

  8. Java ThreadLocal的使用案例

    本文以数据库操作Dao为例进行描述ThreadLocal的使用,如下是一个反例: package com.daxin.threadlocal.dao; import java.sql.Connecti ...

  9. 理解Java ThreadLocal

    ThreadLocal是什么 早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地 ...

  10. Java ThreadLocal (Java代码实战-006)

    ThreadLocal解决什么问题 由于 ThreadLocal 支持范型,如 ThreadLocal< StringBuilder >,为表述方便,后文用 变量 代表 ThreadLoc ...

随机推荐

  1. Delphi - 获取文件大小

    GetFileSize获取文件大小 封装成如下函数,可以直接使用: ///函数功能:获取文件大小,单位取KB,小数自动进位 ///参数:sFilePath文件全路径 ///Result: 成功是返回文 ...

  2. DOM的高级操作-一种JS控制元素的视觉假象

    1.运动中的边界处理(让其在一个指定区域内运动) 当元素的offsetLeft值超出一定距离或达到一个我们想要设置的边界值时,停止计时器. var timer; timer = setInterval ...

  3. CodeForces 1082 E Increasing Frequency

    题目传送门 题意:给你n个数和一个c, 现在有一个操作可以使得 [ l, r ]区间里的所有数都加上某一个值, 现在问你c最多可以是多少. 题解: pre[i] 代表的是 [1,i] 中 c 的个数是 ...

  4. 楼房重建 HYSBZ - 2957

    楼房重建 HYSBZ - 2957 第一次写分块, 写了之后觉得真的是暴力的一比. 题解:先讲n分成 sqrt(n)块,记得补上末尾的, 然后就是对于每一次更新操作, 都重新的讲这个块里面的有效楼放入 ...

  5. 面向对象程序设计(Java) 第1周学习指导及要求

    面向对象程序设计(Java)第1周学习指导及要求 (2019.8.30-2019.9.2)   学习目标 了解课程上课方式及老师教学要求,掌握课程学习必要的软件工具: 理解JVM.JRE与JDK等概念 ...

  6. 自定义Hive UDAF 实现相邻去重

    内置的两个聚合函数(UDAF) collect_list():多行字符串拼接为一行collect_set():多行字符串拼接为一行并去重多行字符串拼接为一行并相邻去重UDAF:Concat() con ...

  7. 【Offer】[37] 【序列化二叉树】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 请实现两个函数,分别用来序列化和反序列化二叉树. 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得 ...

  8. Oracle sqlldr 在DOS窗口导入多列数据到数据库表

    sqlldr 用法详见:https://www.cnblogs.com/rootq/archive/2009/03/01/1401061.html 测试内容: 1.创建数据库表: create tab ...

  9. Go语言基础之网络编程

    现在我们几乎每天都在使用互联网,我们前面已经学习了如何编写Go语言程序,但是如何才能让我们的程序通过网络互相通信呢?本章我们就一起来学习下Go语言中的网络编程. 关于网络编程其实是一个很庞大的领域,本 ...

  10. 059 Python计算生态概览

    目录 一.概要 二.导学 三.实践能力 一.概要 从数据处理到人工智能 实例15-霍兰德人格分析雷达图 从Web解析到网络空间 从人机交互到艺术设计 实例16-玫瑰花绘制 二.导学 纵览Python计 ...