ThreadLocal分析
ThreadLocal使用
每个线程对象,内部创建一个ThreadLocal,并对其赋值,由于后期要使用ThreadLocal.ThreadLocalMap,这个内部类的父类就是最开始创建的ThreadLocal。
public class ThreadLocalTest implements Runnable{
    private static final Logger LOG = LoggerFactory.getLogger(ThreadLocalTest.class);
    private static ThreadLocal<String> threadLocal = new ThreadLocal<String>() {
        @Override
        protected String initialValue() {
            return Thread.currentThread().toString()+"xxx";
        }
    };
    @Override
    public void run() {
        System.out.println("..."+threadLocal.get());
    }
}
class Test {
    public static void main(String[] args) {
        //每个线程都有一个ThreadLocal
        new Thread(new ThreadLocalTest()).start();
        new Thread(new ThreadLocalTest()).start();
        new Thread(new ThreadLocalTest()).start();
    }
}
hibernate中的例子
首先说明ThreadLocal存放的值是线程内共享的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递,这样处理后,能够优雅的解决一些实际问题,比如hibernate中的OpenSessionInView,就是使用ThreadLocal保存Session对象,还有我们经常用ThreadLocal存放Connection,代码如:
public class ConnectionManager {  
  
    /** 线程内共享Connection,ThreadLocal通常是全局的,支持泛型 */  
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();  
      
    public static Connection getCurrConnection() {  
        // 获取当前线程内共享的Connection  
        Connection conn = threadLocal.get();  
        try {  
            // 判断连接是否可用  
            if(conn == null || conn.isClosed()) {  
                // 创建新的Connection赋值给conn(略)  
                // 保存Connection  
                threadLocal.set(conn);  
            }  
        } catch (SQLException e) {  
            // 异常处理  
        }  
        return conn;  
    }  
      
    /** 
     * 关闭当前数据库连接 
     */  
    public static void close() {  
        // 获取当前线程内共享的Connection  
        Connection conn = threadLocal.get();  
        try {  
            // 判断是否已经关闭  
            if(conn != null && !conn.isClosed()) {  
                // 关闭资源  
                conn.close();  
                // 移除Connection  
                threadLocal.remove();  
                conn = null;  
            }  
        } catch (SQLException e) {  
            // 异常处理  
        }  
    }  
}  
- 这样处理的好处:
- 统一管理Connection;
- 不需要显示传参Connection,代码更优雅;
- 降低耦合性;
ThreadLocal方法:
get/set/initValue/remove
get方法
返回此线程局部变量的当前线程副本中的值。如果这是线程第一次调用该方法,则创建并初始化此副本。
get代码,在某个ThreadLocal中执行,get代码如下:
  public T get() {
        Thread t = Thread.currentThread();
        //获取线程中的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //获取Entry弱引用
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
setInitialValue中会做二次判断,这个线程中到底有没有ThreadLocalMap。当然,这么做也是第一次执行setInitialValue的时候需要用。
   private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
第一次调用get方法,setInitialValue会调用ThreadLocal.createMap方法,创建ThreadLocalMap。代码如下:
createMap代码
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
将这个ThreadLocal和value值对应,这个ThreadLocalMap被线程的threadLocals引用,获取也是从线程中获取,因此,线程中维护一个ThreadLocalMap。以后的ThreadLocal和键值对会被传入这Map中。ThreadLocal中有个全局的,自动产生threadLocalHashCod的机制。代码如下:
private final int threadLocalHashCode = nextHashCode();
private static int nextHashCode() {
    return nextHashCode.getAndAdd(HASH_INCREMENT);
}
set
ThreadLocal的set方法执行的是内置map的set方法:map.set(this, value);
每个ThreadLocal对象,都具有自己的hashCode,一个线程的全部ThreadLocal的ThreadLocalMap都存放在线程中。
map.set代码如下:
    private void set(ThreadLocal<?> key, Object value) {
        Entry[] tab = table;
        int len = tab.length;
        //这里调用key.threadLocalHashCode会生成一个新的hash码
        int i = key.threadLocalHashCode & (len-1);
        //找到一个空的位置
        for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
            ThreadLocal<?> k = e.get();
            //获取的是ThreadLocal
            if (k == key) {
                e.value = value;
                return;
            }
            //未存在ThreadLocal,替换这个ThreadLocal
            if (k == null) {
                replaceStaleEntry(key, value, i);
                return;
            }
        }
        
        tab[i] = new Entry(key, value);
        int sz = ++size;
        if (!cleanSomeSlots(i, sz) && sz >= threshold)
            rehash();
    }
remove
remove方法调用的map的remove,
 private void remove(ThreadLocal<?> key) {
        Entry[] tab = table;
        int len = tab.length;
        int i = key.threadLocalHashCode & (len-1);
        for (Entry e = tab[i];
             e != null;
             e = tab[i = nextIndex(i, len)]) {
            if (e.get() == key) {
                e.clear();
                expungeStaleEntry(i);
                return;
            }
        }
    }
附:Reference
public abstract class Reference<T> {
    //等待被gc处理的对象
    private T referent; 
    public T get() {
        return this.referent;
    }        
    public void clear() {
        this.referent = null;
    }
    ...
}
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号