先考虑一个问题,对于用户的session用得比较多,一般就从request.getSession()OK了,但有时不方便能拿到request,像dwr登录、自定义标签等,更不可能依次当参数传下去。那好,定义一个全局的session变量,类似常量的处理。每次访问时重置一下就行了,问题好像解决了!
但考虑过并发问题吗?两个人登录,A置成自己的session了,B又置成他的session了,两人开始打架了,是不是。我们还能做什么吗?答案当然是肯定的。
我们引入ThreadLocal,多么伟大的发明啊!
首先它不是用来解决多线程并发共享一类问题的,它解决的是在一个线程中参数的传递。
下面来看一个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;
}
想象一下这里的threadSession.get()和threadSession.set(s),都做了什么事?
一个猜想:有个全局的共享类,也许是个Map,key就是当前Thread线程,value是这里的s。
变量定义
|
key
|
value
|
操作
|
threadSession
|
T1
|
session1
|
Get、set(s)
|
T2
|
session2
|
Get、set(s)
|
T3
|
Session3
|
Get、set(s)
|
下面来看看ThreadLocal的实现原理(jdk1.5源码)
public class ThreadLocal<T> {
/**
* ThreadLocals rely on per-thread hash maps attached to each thread
* (Thread.threadLocals and inheritableThreadLocals). The ThreadLocal
* objects act as keys, searched via threadLocalHashCode. This is a
* custom hash code (useful only within ThreadLocalMaps) that eliminates
* collisions in the common case where consecutively constructed
* ThreadLocals are used by the same threads, while remaining well-behaved
* in less common cases.
*/
private final int threadLocalHashCode = nextHashCode();
/**
* The next hash code to be given out. Accessed only by like-named method.
*/
private static int nextHashCode = 0;
/**
* The difference between successively generated hash codes - turns
* implicit sequential thread-local IDs into near-optimally spread
* multiplicative hash values for power-of-two-sized tables.
*/
private static final int HASH_INCREMENT = 0x61c88647;
/**
* Compute the next hash code. The static synchronization used here
* should not be a performance bottleneck. When ThreadLocals are
* generated in different threads at a fast enough rate to regularly
* contend on this lock, memory contention is by far a more serious
* problem than lock contention.
*/
private static synchronized int nextHashCode() {
int h = nextHashCode;
nextHashCode = h + HASH_INCREMENT;
return h;
}
/**
* Creates a thread local variable.
*/
public ThreadLocal() {
}
/**
* Returns the value in the current thread's copy of this thread-local
* variable. Creates and initializes the copy if this is the first time
* the thread has called this method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
return (T)map.get(this);
// Maps are constructed lazily. if the map for this thread
// doesn't exist, create it, with this ThreadLocal and its
// initial value as its only entry.
T value = initialValue();
createMap(t, value);
return value;
}
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Many applications will have no need for
* this functionality, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current threads' copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
* @param map the map to store.
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
.......
/**
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread. To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
static class ThreadLocalMap {
........
}
}
这个ThreadLocalMap 类是ThreadLocal中定义的内部类,但是它的实例却用在Thread类中:
public class Thread implements Runnable {
......
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
......
}
存储关系示意图
|
key
|
value
|
操作
|
T1. ThreadLocalMap
|
threadSession
|
session 1
|
Get、set(s)
|
T2. ThreadLocalMap
|
threadSession
|
session 2
|
Get、set(s)
|
T3. ThreadLocalMap
|
threadSession
|
session 3
|
Get、set(s)
|
可以扩展为
|
key
|
value
|
操作
|
T1. ThreadLocalMap
|
threadSession
|
session1
|
Get、set(s)
|
T1. ThreadLocalMap
|
threadV1
|
V1
|
Get、set(v)
|
T1. ThreadLocalMap
|
threadV2
|
V2
|
Get、set(v)
|
|
|
|
|
T2. ThreadLocalMap
|
threadSession
|
session 2
|
Get、set(s)
|
T3. ThreadLocalMap
|
threadSession
|
session 3
|
Get、set(s)
|
它为每个线程创建了一个map,而不是全局共享的map。这样做的好处到底是什么?
下面举一个例子(特别感谢小魏同学)说明这个关系:我们要去住宾馆是要完成的任务(或请求),每个房间就是一个个的线程,并了房间我们把钱包放桌上,睡觉,带上钱包,离开宾馆。这里放包的桌子是一个ThreadLocalMap,我放那,再取走一定是我的。可以放钱包、放衣服、放鞋子都可以。
上面的例子同样可以解释一下它不能解决实际需要共享的变量的并发访问问题,如每个房间的人都要给前台打电话,那么还是会有占线的问题。
但要注意,不能乱用,如果你没有放钱包,就要去取钱包,有可能没有,或者取到别人的(因为钱包是不会真正“拿走”的)。什么东西都要先放那儿,再去取。
另外,jdk1.5的实现与我们上面的设想的不同,目前想到的一点,全局的map可能有并发访问的问题,而jdk的实现却解决了这个问题。
分享到:
相关推荐
在传统的多线程Web应用中,由于多个线程可能会处理同一个请求,如果直接在全局变量中存储session信息,可能会导致线程安全问题。而ThreadLocal提供了一个线程局部的存储空间,每个线程都有自己的ThreadLocal变量...
理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal
- 不要将ThreadLocal用作全局变量,否则可能导致内存泄漏。 - 使用ThreadLocal时,要特别注意线程结束后的清理工作,防止内存泄漏。 - 避免过度使用ThreadLocal,因为它会为每个线程创建额外的内存开销。 以上就是...
java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...
**标题:“JDK的ThreadLocal理解(一)使用和测试”** **正文:** ThreadLocal是Java中的一个非常重要的线程安全工具类,它在多线程编程中扮演着独特的角色。通过创建ThreadLocal实例,我们可以为每个线程提供一个...
`ThreadLocal`是Java平台提供的一种线程局部变量的解决方案,它为每一个使用该变量的线程都提供了独立的变量副本,使得每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这不同于普通的静态...
1. **线程安全的缓存**: 在多线程环境下,每个线程需要有自己的缓存,而不是共享同一个全局缓存,防止数据错乱。 2. **线程相关的配置**: 如数据库连接、事务管理等,每个线程维护自己的配置,避免线程间干扰。 3....
【ThreadLocal模式管理Session的理解】 在使用Hibernate进行数据库操作时,正确管理Session是优化系统性能的关键。Session由SessionFactory创建,而SessionFactory是线程安全的,这意味着它可以被多个并发线程共享...
标题“Hibernage_Session_Manager_ThreadLocal”涉及到的是Hibernate框架中的一种优化策略——使用ThreadLocal管理Session。在Java Web开发中,Hibernate是一个非常流行的ORM(对象关系映射)框架,它帮助开发者将...
总结来说,ThreadLocal是Java中解决多线程数据隔离问题的有效工具,通过为每个线程提供独立的变量副本,它能够在不引入复杂同步机制的情况下,实现线程安全的代码编写。在设计需要线程安全的类或组件时,ThreadLocal...
ThreadLocal 解决了一个重要的问题,即每个线程中都需要一个独立的变量,该变量只能被当前线程访问,而其他线程无法访问。这解决了线程安全问题,因为 ThreadLocal 类型的变量只有自身的线程可以访问。 例如,在...
ThreadLocal是Java编程中一种非常特殊的变量类型,它主要用于在多线程环境下为每个线程提供独立的变量副本,从而避免了线程间的数据共享和冲突。然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将...
- 不要将ThreadLocal用作全局变量,因为它们只在创建它们的线程内有效,无法跨线程共享。 - 谨慎处理生命周期管理,尤其是在静态变量中使用ThreadLocal,确保在不再需要时正确清理,防止内存泄漏。 6. **应用场景...
ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...
javaee开发常见的模式有MVC模式,在C层中常常会再次分层,如:servlet(web层)、service(业务逻辑层)、dao(数据访问层),其中service和dao最容易混在一起,如转...所以,使用ThreadLocal可以解决这样的分层问题。
- 尽量避免将ThreadLocal用作长期持有的全局变量,尤其是在静态方法或静态变量中使用。 - 避免过度依赖ThreadLocal,因为它可能导致设计上的复杂性和难以维护的问题。 综上所述,ThreadLocal是Java多线程编程中的一...
- 不要将ThreadLocal用作全局变量,因为这样可能会导致内存泄漏。 - 尽量避免在静态方法中使用ThreadLocal,因为静态方法没有绑定到特定的线程,可能导致预期之外的行为。 8. **TestClinet.java和SequenceNumber....
### 理解ThreadLocal #### 一、ThreadLocal简介 `ThreadLocal`是一个非常有用的类,它在Java 1.2版本中被引入到`java.lang`包中。其主要功能是在多线程环境中为每个线程提供独立的变量副本,从而避免了线程之间的...