下面来看一个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,再将session set到线程中,实际是放到当前线程的ThreadLocalMap这个map中,这时,对于这个session的唯一引用就是当前线程中的那个ThreadLocalMap(下面会讲到),而threadSession作为这个值的key,要取得这个session可以通过threadSession.get()来得到,里面执行的操作实际是先取得当前线程中的ThreadLocalMap,然后将threadSession作为key将对应的值取出。这个session相当于线程的私有变量,而不是public的。
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 { ........ } }
private final int threadLocalHashCode = nextHashCode(); private static int nextHashCode = 0; private static final int HASH_INCREMENT = 0x61c88647;
private final int threadLocalHashCode = nextHashCode();那么nextHashCode()做了什么呢:
private static synchronized int nextHashCode() { int h = nextHashCode; nextHashCode = h + HASH_INCREMENT; return h; }就是将ThreadLocal类的下一个hashCode值即nextHashCode的值赋给实例的threadLocalHashCode,然后nextHashCode的值增加HASH_INCREMENT这个值。
ThreadLocalMap map = Thread.currentThread().threadLocals;这个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; ...... }再看这句:
if (map != null) map.set(this, value);也就是将该ThreadLocal实例作为key,要保持的对象作为值,设置到当前线程的ThreadLocalMap 中,get()方法同样大家看了代码也就明白了,ThreadLocalMap 类的代码太多了,我就不帖了,自己去看源码吧。
ThreadLocal原理分析,布布扣,bubuko.com
原文:http://blog.csdn.net/aigoogle/article/details/21974261