概述
我们知道 Spring 通过各种 DAO 模板类降低了开发者使用各种数据持久技术的难度。这些
模板类都是线程安全的,也就是说,多个 DAO 可以复用同一个模板实例而不会发生冲突。
我们使用模板类访问底层数据,根据持久化技术的不同,模板类需要绑定数据连接或会话的
资源。但这些资源本身是非线程安全的,也就是说它们不能在同一时刻被多个线程共享。
虽然模板类通过资源池获取数据连接或会话,但资源池本身解决的是数据连接或会话的缓存
问题,并非数据连接或会话的线程安全问题。
按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用
synchronized 进行线程同步。但 Spring 的 DAO 模板类并未采用线程同步机制,因为线
程同步限制了并发访问,会带来很大的性能损失。
此外,通过代码同步解决性能安全问题挑战性很大,可能会增强好几倍的实现难度。那模板
类究竟仰丈何种魔法神功,可以在无需同步的情况下就化解线程安全的难题呢?答案就是
ThreadLocal!
ThreadLocal 在 Spring 中发挥着重要的作用,在管理 request 作用域的 Bean、事务管
理、任务调度、AOP 等模块都出现了它们的身影,起着举足轻重的作用。要想了解 Spring
事务管理的底层技术,ThreadLocal 是必须攻克的山头堡垒。
ThreadLocal 是什么
早在 JDK 1.2 的版本中就提供 java.lang.ThreadLocal,ThreadLocal 为解决多线程程序
的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
ThreadLocal 很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal
并不是一个 Thread,而是 Thread 的局部变量,也许把它命名为 ThreadLocalVariable
更容易让人理解一些。
当使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该变量的线程提供独立的变量
副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
线程局部变量并不是 Java 的新发明,很多语言(如 IBM IBM XL FORTRAN)在语法层面
就提供线程局部变量。在 Java 中没有提供在语言级支持,而是变相地通过 ThreadLocal
的类提供支持。
所以,在 Java 中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没
有在 Java 开发者中得到很好的普及。