ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。
归纳了两点:
1:每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2:将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
ThreadLoacal的应用场景应该为每一个线程对应一个实例,并且这个实例会在很多地方用到,例如数据库连接池对于数据库连接对象的管理,多线程的情况下我们当然可以采用Syn关键字对于获取数据库连接的对象进行加锁,但这样效率不高,因此我们便可以采用框架中的做法,下面请看例子。
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; }
这段代码是Hibernate中对于sqlsession对象的管理,我们可以看到,当多线程执行此方法时,首先判断当前对象有没有放入进去session对象,没有则创建并放入。
这是其种类的get()方法
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} 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) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
对该方法的简单理解
1. 首先获取当前线程
2. 根据当前线程获取一个Map
3. 如果获取的Map不为空,则在Map中以ThreadLocal的引用作为key来在Map中获取对应的value e,否则转到5
4. 如果e不为null,则返回e.value,否则转到5
5. Map为空或者e为空,则通过initialValue函数获取初始值value,然后用ThreadLocal的引用和value作为firstKey和firstValue创建一个新的Map