首先,
ThreadLocal
不是用来解决共享对象的多线程访问问题的,一般情况下,通过
ThreadLocal.set()
到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。
各个线程中访问的是不同的对象。
另外,说
ThreadLocal
使得各线程能够保持各自独立的一个对象,并不是通过
ThreadLocal.set()
来实现的,而是通过每个线程中进行
new
对象操作来创建对象,每个线程创建一个,不是什么对象的拷贝或副本。
通过
ThreadLocal.set()
将这个新创建的对象的引用保存到各线程自己的一个
map
(
ThreadLocalMap
)中,每个线程都有这样一个
map
,执行
ThreadLocal.get()
时,各线程从自己的此
map
(
ThreadLocalMap
)中取出放进去的对象,因此取出来的是各线程自己的对象,
ThreadLocal
实例是作为
map
的
key
来使用的。
如果
ThreadLocal.set()
进去的东西本来就是多个线程共享的同一个对象,那么多个线程的
ThreadLocal.get()
取得的还是这个共享对象本身,还是有并发访问问题。
下面来看一个
hibernate
中典型的
ThreadLocal
的应用:
写道
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
可以看到在
getSession()
方法中,首先判断当前线程中有没有放进去
Session
对象,如果还没有,那么通过
sessionFactory().openSession()
来创建一个
Session
对象(
s
),再将此
session set
到线程中,实际是作为
value
放到当前线程的
ThreadLocalMap
这个
map
中,这时,对于这个
session
的唯一引用就是当前线程中的那个
ThreadLocalMap
(下面会讲到),而
threadSession
是这个
map
中的
key
,要取得这个
session
可以通过
threadSession.get()
来得到,里面执行的操作实际是先取得当前线程中的
ThreadLocalMap
,然后将
threadSession
作为
key
将对应的值(
session
)取出。这个
session
相当于线程的私有变量,而不是
public
的。
显然,其他线程中是取不到这个
session
的,他们也只能取到自己的
ThreadLocalMap
中的东西。要是
session
是多个线程共享使用的,那还不乱套了。
试想如果不用
ThreadLocal
怎么来实现呢?可能就要在
action
中创建
session
,然后把
session
一个个传到
service
和
dao
中,这可够麻烦的。或者可以自己定义一个静态的
map
,将当前
thread
(
Thread.currentThread()
)作为
key
,创建的
session
作为
value
,
put
到
map
中,应该也行,这也是一般人的想法,但事实上,
ThreadLocal
的实现刚好相反,它是在每个线程中有一个
map
(
ThreadLocalMap
),而将
ThreadLocal
实例作为
key
,这样每个
map
中的项数很少,而且当线程销毁时相应的东西也一起销毁了,不知道除了这些还有什么其他的好处。
总之,
ThreadLocal
不是用来解决多线程访问共享对象问题的,而主要是提供了一种保存对象的方法和一种方便的避免参数传递麻烦的对象访问方式。归纳了两点:
1
、每个线程中都有一个自己的
ThreadLocalMap
类对象,可以将线程自己的对象(作为
value
)保持到其中,各管各的,线程可以正确的访问到自己的对象。
2
、将一个共用的
ThreadLocal
静态实例作为
key
,将不同对象的引用保存到不同线程的
ThreadLocalMap
中,然后在线程执行的各处通过这个静态
ThreadLocal
实例的
get()
方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
当然如果要把本来线程共享的对象通过
ThreadLocal.set()
放到线程中也可以,可以实现避免参数传递的访问方式,但是要注意
get()
到的是那同一个共享对象,并发访问问题要靠其他手段来解决。但一般来说线程共享的对象通过设置为某类的静态变量就可以实现方便的访问了,似乎没
必要放到线程中。
ThreadLocal
的应用场合,我觉得最适合的是按每个线程对应一个实例的方式访问对象,并且这个对象很多地方都要用到。比如:
一个验证流程包括很多验证环节,每个验证环节用一个类(
validator
)表示,每个验证环节都要用到同一个对象(比如会员类型:
memberType
),也就是说这个
memberType
要在整个验证流程中的各验证环节进行传递。一般的做法是将此对象作为方法的一个参数一个个传到各验证环节中去。
这种场景下就很适合采用
ThreadLocal
来实现。一个线程(这个场景下即一个验证流程)要用到一个对象实例(
memberType
),而这个对象要在很多地方(每个验证环节)都用到。
看ThreadLocal类的源码可知作为ThreadLocal实例的变量只有 threadLocalHashCode 这一个,而且是final的,用来区分不同的ThreadLocal实例,ThreadLocal类主要是作为工具类来使用。nextHashCode 和HASH_INCREMENT 是ThreadLocal类的静态变量,实际上HASH_INCREMENT是一个常量,表示了连续分配的两个ThreadLocal实例的threadLocalHashCode值的增量,而nextHashCode 的表示了即将分配的下一个ThreadLocal实例的threadLocalHashCode 的值。
分享到:
相关推荐
正确理解ThreadLocal.pdf
理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal
ThreadLocal应用示例及理解,这个写了相关的示例,可以参考一下。
ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量
并且由于每个线程在访问该变量时,读取和修改的,都是独有的那份变量拷贝,变量被彻底封闭在每个访问的线程中,并发错误出现的可能也完全消除了。} catch (SQL
ThreadLocal入门教程。 讲解了线程安全和ThreadLocal的使用的基本知识。
ThreadLocal
ThreadLocal深度理解
主要介绍了深入理解ThreadLocal工作原理及使用示例,涉及ThreadLocal<T> 简介和使用示例及ThreadLocal的原理等相关内容,具有一定参考价值,需要的朋友可以了解下。
Java中ThreadLocal工具类(解决多线程程序中并发问题的一种新思路,主要为参数的拷贝问题),感兴趣的话可以查看博文,博文地址:http://blog.csdn.net/otengyue/article/details/38459327
ThreadLocal的简单理解.doc
学习ThreadLocal,了解其中的原理,以及学习其中的优点!避免坑点!!
DbUTils中用ThreadLocal类
主要介绍ThreadLocal的原理,实例分析以及注意事项
java 简单的ThreadLocal示例
ThreadLocal的几种误区ThreadLocal的几种误区ThreadLocal的几种误区
Synchronized与ThreadLocal