ThreadLocal是用来处理多线程并发问题的一种解决方案。ThreadLocal是的作用是提供线程的局部变量,在多线程并发环境下,提供了与其他线程隔离的局部变量。通常这样的设计的情况是因为这个局部变量是不适合放在全局变量进行同步处理的。比如在事务管理中,在service类中的涉及到事务的方法,每个事务的上下文都应该是独立拥有数据库的connection连接的,否则在数据提交回滚过程中就会产生冲突。
spring中使用ThreadLocal来设计TransactionSynchronizationManager类,实现了事务管理与数据访问服务的解耦,同时也保证了多线程环境下connection的线程安全问题。
DataSourceTransactionManager的实现中,doBegin()方法开启事务,我们看下它是怎么处理connection资源的。
首先从数据库连接池中获得一个connection,并构造一个connection包装类,使用这个包装类开启事务,最后通过TransactionSynchronizationManager将connection与ThreadLocal绑定,事务提交或者回滚后,解除绑定。
TransactionSynchronizationManager中bindResource()的实现
Resource就是ThreadLocal,而这里的Map就是ThreadLocalMap的value,与当前线程关联的ThreadLocal的值。
ThreadLocal又是如何为每个线程维护一个独立的局部变量的呢?
首先在Thread类中,都会维护一个ThreadLocalMap映射表,这个映射表存储的key是ThreadLocal本身,value则是我们存储的局部变量object。
ThreadLocal类中get方法和set方法的实现。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
我们再看getMap的实现
ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
从代码实现中可以看出,每个线程Thread都会维护自己的ThreadLocalMap,这个map的key则是ThreadLocal类本身,而value则是我们保存的数据。ThreadLocal在多线程中是被公共持有的,被隔离的数据实际是存放在每个线程的ThreadLocalMap中的,只不过是通过ThreadLocal的引用得到每个线程维护的ThreadLocalMap中的value。