1. 什么是ThreadLocal类

JDK官方文档对其定义如下:

This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).

中文解释: 这个类对象会在各个线程有一份自己的拷贝。ThreadLocal一般都定义成static,但是和一般的static变量的区别就是每个线程实际上都有一份该对象的副本。

重点:

  1. 要定义成static的
  2. 线程使用static的ThreadLocal对象,实际使用的是自己拥有的这个ThreadLocal对象的拷贝

某个线程需要在其上下文之间(各个函数之间)共享一个对象,可以考虑使用ThreadLocal。

这里注意下和单纯的static变量的区别。单纯的static变量能够被所有线程共享(所有线程访问的是一个对象)。而一个ThreadLocal对象(即使是static的)只会关联一个线程。也就是满足线程封闭条件。在多线程并发的环境下某个线程对应的ThreadLocal对象肯定是线程安全的。因为只有一个线程会去改动他嘛。

2. 什么时候使用ThreadLocal类

某个线程只想在自己的上下文之间共享一个对象,不受别的线程干扰,可以使用ThreadLocal。当然针对这种需求也可以使用局部标量和普通的static对象加锁。但是这两种方式都有自己的缺点:

  1. 局部变量: 线程内部方法传值要利用参数,很麻烦
  2. 普通static变量加锁: 加锁开销大

由于只在线程内部使用,当然其也是线程安全的。

一般一些线程相关的状态变量、数据库连接对象、缓存对象都可以设置为ThreadLocal。

推荐:针对何时使用TheradLocal可以参考下SF上的问题: When and how should I use a ThreadLocal variable?

3. ThreadLocal在网上的一些误解

ThreadLocal由于每个线程都有自己的副本,所以多线程环境下并不能保证这些副本全部是一致的。也就是说多线程之间,该对象实际上是不同步的。当然如果该对象一开始初始化后是“不变”的话,那么互相之间自然是同步的。网上一些博客在不说明具体场景和条件约束下就认定ThreadLocal能解决多线程同步问题的说法,是不正确的。

不正确的示例: