博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ThreadLocal之我所见
阅读量:5876 次
发布时间:2019-06-19

本文共 2704 字,大约阅读时间需要 9 分钟。

网上有很多关于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优先处理掉,根本无需担心内存泄露问题。

转载地址:http://jzkix.baihongyu.com/

你可能感兴趣的文章
[Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统...
查看>>
Android 网络编程 记录
查看>>
微软同步发行Windows 10和Windows 10 Mobile系统更新
查看>>
Maven 传递依赖冲突解决(了解)
查看>>
Zeppelin的入门使用系列之使用Zeppelin运行shell命令(二)
查看>>
[Spark][Python]Spark Join 小例子
查看>>
form表单下的button按钮会自动提交表单的问题
查看>>
大战设计模式【11】—— 模板方法模式
查看>>
springBoot介绍
查看>>
Intellij IDEA 快捷键整理
查看>>
Redis 通用操作2
查看>>
11. Spring Boot JPA 连接数据库
查看>>
洛谷P2925 [USACO08DEC]干草出售Hay For Sale
查看>>
MapReduce工作原理流程简介
查看>>
那些年追过的......写过的技术博客
查看>>
小米手机解锁bootload教程及常见问题
查看>>
Python内置函数property()使用实例
查看>>
Spring MVC NoClassDefFoundError 问题的解决方法。
查看>>
CentOS 6.9配置网卡IP/网关/DNS命令详细介绍及一些常用网络配置命令(转)
查看>>
python基础教程_学习笔记19:标准库:一些最爱——集合、堆和双端队列
查看>>