网上有很多关于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. 3.键盘输入10个数,放到数组中,(1)去除该数组中大于10的数 (2)将该数组中的数字写入到本地文件number.txt中

    package cn.it.text; import java.io.FileWriter; import java.io.IOException; import java.util.Scanner; ...

  2. Html5 Page Creator,简易h5页面场景制作

  3. 自制操作系统Antz(8)——实现内核 (中) 扩展内核

    Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html 在前几天的任务中,我们已经简单实现了MBR,直接操作显示器和硬盘操作 ...

  4. 彻底清除 Windows 服务

    如果服务已经停止, 或从注册表中删除, 但是在任务管理器中仍能看到服务躺在列表里面. 只需要找到服务的PID, 然后运行命令: taskkill /PID 服务的PID /f 即可.

  5. ValueObject

    ValueObject When programming, I often find it's useful to represent things as a compound混合物. A 2D co ...

  6. Facebook token更新

    How to refresh Facebook access token python代码: 可以用vs code来运行,依赖python2.*,如果使用python3.*可能会出现部分包不兼容 sh ...

  7. bootstrap table 前后端分页(超级简单)

    前端分页:数据库查询所有的数据,在前端进行分页 后端分页:每次只查询当前页面加载所需要的那几条数据 下载bootstrap 下载bootstrap table jquery谁都有,不说了 项目结构:T ...

  8. java基础之集合框架--使用ArrayList类动态 存储数据

    一.ArrayList是List接口下的一个实现类,实现了长度可变的.连续的数组:拥有数组的特性. 遵循了LIst的规则:不唯一的.有序的. 如果没有增加泛型的话,集合中可以添加任何类型的数据. 使用 ...

  9. 8_管理及IO重定向

    五大类:运算器.控制器:CPU存储器:RAM输入设备/输出设备 程序:是由指令和数据组成的 控制器:读取指令运算器:存储器: 地址总线:内存寻址数据总线:传输数据控制总线:控制指令 寄存器:CPU暂时 ...

  10. 关于 Expression is not assignable 错误

    1.在 Build Phases中导入  UIKit.framework 2.在pch中导入头文件 #import <UIKit/UIKit.h> 3.写一个分类 即可解决 贴出分类代码 ...