定义:ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
使用场景:
比如一次请求线程进来,业务 Dao 需要操作两个表。如果是 new 出两个 Connection ,分别不同的 Connection 操作不同的表,就无法保证事务。这时就可以利用 ThreadLocal 存储唯一 Connection 对象。每次请求线程时:
- 会从 ThreadLocal 获取 Connection 对象。如果有,则保证了后面多个数据库操作共用同一个 Connection ,从而保证了事务。
- 如果没有,往 ThreadLocal 新增Connection 对象,并返回到线程
ThreadLocal和Synchronized比较:
都是为了解决多线程中相同变量的访问冲突问题,不同的点是:
- Synchronized是通过线程等待,牺牲时间来解决访问冲突
- ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突
- ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。
正因为ThreadLocal的线程隔离特性,使他的应用场景相对来说更为特殊一些。
当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。
ThreadLocal的使用:
static final ThreadLocal<T> sThreadLocal = new ThreadLocal<T>();
sThreadLocal.set()
sThreadLocal.get()
ThreadLocal的源码解析:
Thread.class
ThreadLocal.ThreadLocalMap threadLocals = null;
每一个新的线程Thread都会实例化一个ThreadLocalMap并赋值给成员变量threadLocals,使用时若已经存在threadLocals则直接使用已经存在的对象。(Thread类有一个成员变量 threadLocals,这个变量的数据类型是 ThreadLocal.ThreadLocalMap。threadLocals保存数据的key是ThreadLocal本身)
ThreadLocalMap.class(它是ThreadLocal的静态内部类)
table = new Entry[INITIAL_CAPACITY];
Entry为ThreadLocalMap静态内部类,它的key为ThreadLocal,value为共享的储值。
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1)
前面讲过每个线程Thread持有一个ThreadLocalMap类型的实例threadLocals,结合此处可以理解成每个线程Thread都持有一个Entry型的数组table,而一切的读取过程都是通过操作这个数组table完成的。