网上有很多关于ThreadLocal的文章,大部分都提到了多线程之间共享资源的问题。其实ThreadLocal和多线程之间一点关系都没有。如果有,我怕是它的名字改成ThreadShare是不是更合适呢?开个玩笑。从其名称ThreadLocal,我们就可以看出他应该是隶属于线程内部的资源。接下来就详细说说吧。

我们以前在处理一个Request请求,穿透多个业务方法的时候,如果要共享数据,一般都会搞个Context上下文对象,在多个方法之间进行传递,这样可以解决多个方法之间的数据共享问题。这是很不错的一种方案,而且这种方案在实际使用的时候效果也非常不错,因为Context内部我们想放什么,就放什么,想怎么放就怎么放,非常的自由无界。但是这种自由带来的问题在小流量的请求中是不会有问题的,但是在大流量的请求中,则存在不小的问题,主要在:

1. Context对象,每个请求进来,都会new一个,大流量下,瞬间暴增,由于空间申请操作势必引发频繁的young GC, 业务压力大的时候,full GC也是不可避免的。

2. Context对象,在一个请求终结之后,需要手动释放。

3. Context对象,存在被请求内部的多线程共享访问的情形。有线程安全性问题。

上面三个问题,是我随便列举的,但是在实际使用中,可能还有更多。但是如果Context的生产和销毁如果控制的足够好的话,上面的问题也不是什么问题。

既然Context对象的控制稍显麻烦,那么JDK有没有提供什么现成的类库供我们使用呢? 答案是肯定的,这个对象就是ThreadLocal对象。

说道ThreadLocal对象,我更认为他是在当前请求的上游和下游之间进行数据共享的。那么按照之前的例子说来,如果一个请求穿越多个业务方法,其实数据的共享可以利用ThreadLocal来进行,这样就无需专门定义一个Context。

首先来看看其内部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)
return (T)e.value;
}
return setInitialValue();
} ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
} 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;
} protected T initialValue() {
return null;
}

从上面源码可以看出,get操作会从当前Thread上附加的map中进行数据获取。

再来看看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 getMap(Thread t) {
return t.threadLocals;
} void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}

从上面源码看出,首先他会取出当前Thread,然后会将map设置到当前Thread上,用户可以在这个map上进行数据增删改查操作。非常巧妙。所以从这里可以看出,一个ThreadLocal对象,即便穿插在多个线程之间,也不会造成资源共享问题,因为他会为每个线程都设置map对象,这也从根本上避免了线程安全问题。

最后,因为ThreadLocal内部的对象为WeakReference,所以不用进行手动释放,只需要保证一个请求结束,对其内部的引用释放掉就行了,然后自动会被JVM优先处理掉,根本无需担心内存泄露问题。

ThreadLocal之我所见的更多相关文章

  1. java并发编程学习: ThreadLocal使用及原理

    多线程应用中,如果希望一个变量隔离在某个线程内,即:该变量只能由某个线程本身可见,其它线程无法访问,那么ThreadLocal可以很方便的帮你做到这一点. 先来看一下示例: package yjmyz ...

  2. java.lang.ThreadLocal的作用和原理?列举在哪些程序中见过ThreadLocal的使用?

    java.lang.ThreadLocal的作用和原理?列举在哪些程序中见过ThreadLocal的使用? 说明类java.lang.ThreadLocal的作用和原理.列举在哪些程序中见过Threa ...

  3. 赌十包辣条,你一定没见过这么通透的ThreadLocal讲解

    1.看个热闹 鉴于普罗大众都喜欢看热闹,咱们先来看个热闹再开工吧! 场景一: 中午了, 张三.李四和王五一起去食堂大菜吃饭.食堂刚经营不久,还很简陋,负责打菜的只有一位老阿姨. 张三:我要一份鸡腿. ...

  4. Spring使用ThreadLocal技术来处理这些问题

    过去我习惯于从左到右的思考,因为这符合书写的习惯,对于“好”得前端工程师,我们首先可能会去思考什么是好,好的定义和范围,标准和要求?但现在我习惯于从右到左的思考,因为我觉得越是抽象越难以定义,从粒度更 ...

  5. Java并发编程--线程封闭(Ad-hoc封闭 栈封闭 ThreadLocal)

    线程封闭实现好的并发是一件困难的事情,所以很多时候我们都想躲避并发.避免并发最简单的方法就是线程封闭.什么是线程封闭呢?就是把对象封装到一个线程里,只有这一个线程能看到此对象.那么这个对象就算不是线程 ...

  6. ThreadLocal是否会引发内存泄露的分析(转)

    这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...

  7. ThreadLocal本地线程变量的理解

     一般的Web应用划分为展现层.服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用.在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程.       ...

  8. Java多线程学习之ThreadLocal源码分析

    0.概述 ThreadLocal,即线程本地变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.它可以将变量绑定到特定的线程上,使每个线程都拥有改变量的一个拷贝,各线程相同变量间互不 ...

  9. ThreadLocal终极源码剖析

    目录一.ThreadLocal1.1 源码注释1.2 源码剖析      散列算法-魔数0x61c88647      set操作    get操作    remove操作1.3 功能测试1.4 应用 ...

随机推荐

  1. unix socket服务器

    只能处理单个消息,一发一收. int loop(void) {   struct sockaddr_un client_addr;  int server_socket, client_socket; ...

  2. java项目word文件转html文件

    最近在项目开发中用户提出要在电脑上没有装office时在浏览器中打开word文件,最后确定的逻辑:用户选择想要查看的文件,页面js判断文件是否为word.不是执行下载,是后端根据word文件后缀访问对 ...

  3. Liunx网络技术管理及进程管理

    Linux网络技术管理及进程管理(week2_day4)   OSI七层模型和TCP/IP四层模型 OSI七层模型:OSI(Open System Interconnection)开放系统互连参考模型 ...

  4. pyautogui

    pip install PyGetWindow==0.0.1 pip install pyautogui https://www.cnblogs.com/dcb3688/p/4607980.html

  5. algs4 使用 DrJava 编写 Hello World on Windows

    前阶段读了 Yinwang 的博客, 对 Scheme and Lisp 产生了很大的兴趣, 用 学生模式的  DrRacket IDE一步一步开始实现 How to Design Programs. ...

  6. Tomcat在Window控制台下启动时乱码的两种解决办法

    在命令提示符中启动Tomcat时,日志窗口出现乱码: 乱码的原因肯定是日志解码错误引起的,因此就有一系列问题: 1.这个窗口的文本编码是什么? 窗口的文本编码查看:右击窗口>选项 可以看到窗口的 ...

  7. oracle 增加大字段项

    --不同类型增加大字段项 alter table 表名 add 新增一个字段B clob; --将需要改成大字段的项内容copy到大字段中 update 表名 set 新增一个字段B=字段A; --将 ...

  8. Java 问题定位工具 ——jstack

    简介 jstack 主要用于生成虚拟机当前时刻的「线程快照」.线程快照是当前 Java 虚拟机每一条线程正在执行的方法堆栈的集合. 生成线程快照的主要目的是用于定位线程出现长时间停顿的原因,如线程间死 ...

  9. select样式重置

                div{                 //用div的样式代替select的样式                 width: 200px;                 ...

  10. [opengl]Clion配置opengl

    如何在Clion中编写Opengl程序 首先下载 GLAD GLFW 创建Clion工程 在工程中创建文件夹lib.dll.include文件夹 把下载下来的东西放入对应的文件夹 CMakeLists ...