ThreadLocal也是在面试过程中经常被问到的,本文主要从以下三个方面来谈对ThreadLocal的一些理解:

  • ThreadLocal用在什么地方
  • ThreadLocal一些细节
  • ThreadLocal的最佳实践

ThreadLocal用在什么地方?

讨论ThreadLocal用在什么地方前,我们先明确下,如果仅仅就只有一个线程,那么都不用谈ThreadLocal,ThreadLocal是用在多线程的场景的

ThreadLocal归纳下来就2类用途:

  • 保存线程上下文信息,在任意需要的地方可以获取
  • 线程安全的,避免某些情况需要考虑线程安全必须同步带来的性能损失

保存线程上下文信息,在任意需要的地方可以获取

由于ThreadLocal的特性,同一线程在某地方进行设置,在随后的任意地方都可以获取到。从而可以用来保存线程上下文信息。

常用的比如每个请求怎么把一串后续关联起来,就可以用ThreadLocal进行set,在后续的任意需要记录日志的方法里面进行get获取到请求id,从而把整个请求串起来。

还有比如Spring的事务管理,用ThreadLocal存储Connection,从而各个DAO可以获取同一Connection,可以进行事务回滚,提交等操作。

hreadLocal的这种用处,很多时候是用在一些优秀的框架里面的,一般我们很少接触,反而下面的场景我们接触的更多一些!

线程安全的,避免某些情况需要考虑线程安全必须同步带来的性能损失

ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。但是ThreadLocal也有局限性,我们来看看阿里规范:

每个线程往ThreadLocal中读写数据是线程隔离,互相之间不会影响的,所以ThreadLocal无法解决共享对象的

更新问题!

由于不需要共享信息,自然就不存在竞争问题了,从而保证了某些情况下线程的安全,以及避免了某些情况需要考虑线程安全必须同步带来的性能损失

这类场景阿里规范里面也提到了:

ThreadLocal一些细节

ThreaLocal使用示例代码:

public class ThreadLocalTest {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
threadLocal.set(i);
System.out.println(Thread.currentThread().getName() + "====" + threadLocal.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
threadLocal.remove();
}
}, "threadLocal1").start(); new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "====" + threadLocal.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
threadLocal.remove();
}
}, "threadLocal2").start();
}
}

代码运行结果:

从运行的结果我们可以看到threadLocal1进行set值对threadLocal2并没有任何影响!

Thread、ThreadLocalMap、ThreadLocal总览图:

Thread类有属性变量threadLocals (类型是ThreadLocal.ThreadLocalMap),也就是说每个线程有一个自己的ThreadLocalMap ,所以每个线程往这个ThreadLocal中读写隔离的,并且是互相不会影响的。

一个ThreadLocal只能存储一个Object对象,如果需要存储多个Object对象那么就需要多个ThreadLocal

如图:

看到上面的几个图,大概思路应该都清晰了,我们Entry的key指向ThreadLocal用虚线表示弱引用 ,下面我们来看看ThreadLocalMap:

java对象的引用包括 :强引用,软引用,弱引用,虚引用 。

因为这里涉及到弱引用,简单说明下:

弱引用是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,如果该对象仅仅被弱引用关联,那么就会被回收。

当仅仅只有ThreadLocalMap中的Entry的key指向ThreadLocal的时候,ThreadLocal会进行回收的

ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,但是Entry是强引用,那么Entry里面存储的Object,并没有办法进行回收,所以ThreadLocalMap 做了一些额外的回收工作。

ThreadLocal的最佳实践!

很多时候,我们都是用在线程池的场景,程序不停止,线程基本不会销毁

由于线程的生命周期很长,如果我们往ThreadLocal里面set了很大很大的Object对象,虽然set、get等等方法在特定的条件会调用进行额外的清理,但是ThreadLocal被垃圾收集器回收后,在ThreadLocalMap里对应的Entry的键会变成null,但是后续在也没有操作set、get等方法了。

所以最佳实践,应该在我们不使用的时候,主动调用remove方法进行清理。

这里把ThreadLocal定义为static还有一个好处就是,由于ThreadLocal有强引用在,那么在ThreadLocalMap里对应的Entry的键会永远存在,那么执行remove的时候就可以正确进行定位到并且删除!!!

最佳实践做法应该为:

抽象为:

try {
// 其它业务逻辑
} finally {
threadLocal对象.remove();
}

思考

如果面试的时候,可以把上面的内容都可以讲到,个人觉得就非常好了,回答的就挺完美了。但是如果你可以进行下面的回答,那么就更完美了。

对于ThreadLocal,我在看Netty源码的时候,还了解过FastThreadLocal,xxxxx列一些内容。那就是一个升级了。实际上,FastThreadLocal的吞吐量比ThreadLocal高很多。

对ThreadLocal的一些理解的更多相关文章

  1. Java中ThreadLocal的深入理解

    官方对ThreadLocal的描述: "该类提供了线程局部(thread-local)变量.这些变量不同于它们的普通对应物,因为访问某个变量(通过其get或set方法)的每个线程都有自己的局 ...

  2. ThreadLocal类的理解

    首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的.各 ...

  3. 谈谈对ThreadLocal类的理解

    源码中对于ThreadLocal类的解释是: /** * This class provides thread-local variables. These variables differ from ...

  4. ThreadLocal的简单理解

    目录 一.背景 二.ThreadLocal解决的问题 三.如何创建一个ThreadLocal实例 四.ThreadLocal如何做到线程变量隔离 1.理解3个类 2.看下set方法是如何实现的 3.看 ...

  5. ThreadLocal()理解

    在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序. 当使用 ...

  6. Android开发之ThreadLocal原理深入理解

    [Android]ThreadLocal的定义和用途 ThreadLocal用于实现在不同的线程中存储线程私有数据的类.在多线程的环境中,当多个线程需要对某个变量进行频繁操作,同时各个线程间不需要同步 ...

  7. 理解ThreadLocal(之二)

    想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码 ...

  8. 正确理解ThreadLocal

    想必很多朋友对 ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理 解,然后根据ThreadLocal类的 ...

  9. ThreadLocal深入理解一

    转载:http://www.cnblogs.com/dolphin0520/p/3920407.html 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使 ...

随机推荐

  1. 多语言应用性能监控系统:Elastic APM

    ▶ 概述 Elastic APM 是基于 Elastic Stack 构建的应用性能监控系统.通过 Elastic APM 可以监控应用程序,收集有关请求的响应时间.数据库查询.高速缓存调用.外部 H ...

  2. (数据科学学习手札65)利用Python实现Shp格式向GeoJSON的转换

    一.简介 Shp格式是GIS中非常重要的数据格式,主要在Arcgis中使用,但在进行很多基于网页的空间数据可视化时,通常只接受GeoJSON格式的数据,众所周知JSON(JavaScript Obje ...

  3. git中常用的操作命令有哪些?常用操作命令归纳

    git中常用的操作命令有哪些?本篇文章就给到大家归纳了一些git中常用操作命令.有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. git开始 全局配置:配置用户名和e-mail地址 1 ...

  4. PCB 板边倒圆角的实现方法(基本算法一)

    PCB外形是直角时外形时,通常工程制作时,外是直角或尖角的地方倒圆角,主要是为了防止板边容易划伤板且容易扎伤人 所以当客户没有特殊要求时,PCB外形是直角时一般会默认倒角0.5mm圆角(如下图所示) ...

  5. 使用flink Table &Sql api来构建批量和流式应用(1)Table的基本概念

    从flink的官方文档,我们知道flink的编程模型分为四层,sql层是最高层的api,Table api是中间层,DataStream/DataSet Api 是核心,stateful Stream ...

  6. Android开发-实现第三方APP跳转

    自己创建一个按钮: <Button android:id="@+id/btn_button" android:layout_width="fill_parent&q ...

  7. sql server编写通用脚本实现获取一年前日期的方法

    问题: 在数据库编程开发中,有时需要获取一年前的日期,以便以此为时间的分界点,查询其前后对应的数据量.例如:1. 想查询截止到一年前当天0点之前的数据量,以及一年前当天0点开始到现在的数据量.2. 想 ...

  8. Java面试题汇总---整理版(附答案)

    今天继续为大家整理Java面试题,并涉及数据库和网络等相关知识,希望能帮助到各位开发者. 1,为什么要用spring,Spring主要使用了什么模式? spring能够很好的和各大框架整合,它通过IO ...

  9. KETTLE数据上传

    1.     KETTLE简介 一种ETL工具,ETL,是英文Extract-Transform-Load的缩写,用来描述将数据从来源端经过抽取(extract).转换(transform).加载(l ...

  10. mybatis学习(五)(动态mybatis(多条件查询))

    有时候要查询条件是多条件的,尤其是使用mybatis的时候如何创建sql语句呢? 这里mybatis有自己的办法,如下: 案例:通过传入map,根据map里面的数据来查询 mapper配置如下: &l ...