2019独角兽企业重金招聘Python工程师标准>>>
什么是ThreadLocal?首先要说明的一点是ThreadLocal并不是一个Thread,而是Thread的局部变量。在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。下面我们就来看看ThreadLocal的初步内容:
多线程安全性解决方案
①进行同步控制synchronized效率降低 并发变同步(串行) ,lock(串行)控制灵活
②使用ThreadLocal 本地线程 每个线程一个变量副本(各不相干)
两种线程安全方案的差异
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而 ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队 访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响,ThreadLocal占用内存较大,但是速度快,而线程同步相对内存占用小,但是速度慢。如果在内存比较充足的情况,对并发部分的执行效率要求很高的话,那么就是ThreadLocal登场的时候了。一般情况下用同步机制还是居多的。
理解ThreadLocal的原理
每个ThreadLocal对象内部有个ThreadLocalMap,当线程访问ThreadLocal对象时,会在线程内部的ThreadLocalMap新建一个Entry,这样的话每个线程都有一个对象的副本,保证了并发场景下的线程安全。我理解ThreadLocal的使用场景是某些对象在多线程并发访问时可能出现问题,比如使用SimpleDataFormat的parse()方法,内部有一个Calendar对象,调用SimpleDataFormat的parse()方法会先调用Calendar.clear(),然后调用Calendar.add(),如果一个线程先调用了add()然后另一个线程又调用了clear(),这时候parse()方法解析的时间就不对了,我们就可以用ThreadLocal
public abstract class TransactionSynchronizationManager {
//线程绑定的资源,比如DataSourceTransactionManager绑定是的某个数据源的一个Connection,在整个
//事务执行过程中 都使用同一个Jdbc Connection
private static final ThreadLocal
//事务注册的事务同步器
private static final ThreadLocal
//事务名称
private static final ThreadLocal
//事务只读属性
private static final ThreadLocal
//事务隔离级别
private static final ThreadLocal
//事务同步开启
private static final ThreadLocal
不是说一遇到并发场景就用ThreadLocal来解决,我们还可以用synchronized或者锁来实现线程安全,ThreadLocal使用不当时会引起内存泄露的问题
ThreadLocal就是变量在不同线程上的副本,不同线程不共享,所以对变量改动时就不需要考虑线程间同步的问题了
ThreadLocal在web应用开发中是一种很常见的技巧,当web端采用无状态写法时(比如stateless session bean和spring默认的singleton),就可以考虑把一些变量放在ThreadLocal中
举个简单例子,你有两个方法A和B都要用到变量userId,又不想传来传去,一个很自然的想法就是把userId设为成员变量,但是在无状态时,这样做就很可能有问题,因为多个request在同时使用同一个instance,userId在不同request下值是不一样的,就会出现逻辑错误
但由于同一个request下一般都是处于同一个线程,如果放在ThreadLocal的话,这个变量就被各个方法共享了,而又不影响其他request,这种情况下,你可以简单把它理解为是一种没有副作用的成员变量
我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中, 绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、 TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用 ThreadLocal进行处理,让它们也成为线程安全的状态。