ThreadLocal详解

ThreadLocal详解

ThreadLocal简介

​ ThreadLocal的实例代表了一个线程局部的变量,每条线程都只能看到自己的值。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本;

它采用空间来换取时间的方式,解决多线程中相同变量的访问冲突问题。

ThreadLocal的简单使用

public class ConnectionUtils {    
    private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();     
    private DataSource dataSource;    
    public void setDataSource(DataSource dataSource) {       			 			
    	this.dataSource = dataSource;   
    }    
    public Connection getThreadConnection() {        
        //1.先从threddLocal中获取        
        Connection connection = tl.get();        
        //2.判断当前线程中是否有connection        
        if (connection == null) {           
            try {      
                connection = dataSource.getConnection();            				
            } catch (SQLException e) {                								
            	e.printStackTrace();           
            }            
            tl.set(connection);        
        }       
        return connection;    
    }    
    /**     * 把连接和线程解绑     */    
    public void removeConnection() {
        tl.remove();    
    }
}

​ 上面的例子中,通过ThreadLocal从当前线程中获取connection,如果当前线程中没有connection,则通过数据源dataSource来创建,并放入到当前线程中;以此来保证每个线程中的connection都是互不影响的。

​ 为什么说通过ThreadLocal来存放变量,就能保证每个线程中的变量是互相独立的呢?下面来看ThreadLocal内部实现。

ThreadLocal的实现原理

首先看ThreadLocal中的set方法
public void set(T value) {
    Thread t = Thread.currentThread();    
    ThreadLocalMap map = getMap(t);    
    if (map != null)        
        map.set(this, value);    
    else        
        createMap(t, value);
}

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

可以看到set方法中先调用了getMap(Thread t)方法,当前线程中的threadLocals;查看下方Thread类

/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

我们可以看到threadLocals为Thread类中的一个成员变量,默认值为null。

再看createMap(Thread t, T firstValue)方法,以当前threadLocal对象为key,set方法中要放入的变量为value,存入到ThreadLocalMap对象中,并赋值给当前线程的成员变量threadLocals(即以当前threadLocal对象为key,要存入的变量为value,存放到当前线程中的容器threadLocals中,类型为ThreadLocalMap)。

下面来看一下ThreadLocalMap

static class ThreadLocalMap {    
    /**     * The entries in this hash map extend WeakReference, using     			
    		* its main ref field as the key (which is always a    
    		* ThreadLocal object).  Note that null keys (i.e.entry.get() 
    		* == null) mean that the key is no longer referenced, so the    	 	
    		*  entry can be expunged from table.  Such entries are	referred to    
           * as "stale entries" in the code that follows.     */    		
           static class Entry extends WeakReference<ThreadLocal<?>> {        
               /** The value associated with this ThreadLocal. */        			
               	Object value;        
           		Entry(ThreadLocal<?> k, Object v) {            
               	super(k);            
               	value = v;       
           }    
     }    
    /**     * The initial capacity -- MUST be a power of two.     */    	
    private static final int INITIAL_CAPACITY = 16;    
    /**     * The table, resized as necessary.    
    		* table.length MUST always be a power of two.     */    
    private Entry[] table;

ThreadLocalMap为ThreadLocal类中的一个内部类,它通过自己的内部类Entry,自己实现了一个类似Map的结构,其中可以存放多组键值对类型的数据(存放到成员变量table中)。

再看ThreadLocal中的get方法
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();
}

从上面可以看出,get方法中也是先通过当前线程获取当前线程中的ThreadLocalMap类型的成员变量threadLocals,如果不为null,再通过当前ThreadLocal对象来获取set方法中存放的value,如果为null,则返回默认值(如果没有设置默认值,则为null)。

再看ThreadLocal中的remove方法
public void remove() {    
    ThreadLocalMap m = getMap(Thread.currentThread());    
    if (m != null)        
        m.remove(this);
}

remove方法时jdk1.5之后才有的方法,其目的是为了让用户可以手动删除存入到ThreadLocal中的变量(不删除也没关系,存入的变量会随着线程的销毁而销毁)

小结

其实ThreadLocal的实现就是将不能被线程共享的变量(即有状态的变量),以当前threadLocal对象为key,要存入的变量为value,存放的到当前线程中的容器threadLocals(此容器的类型ThreadLocalMap,是自己实现的一种类似Map的结构)中;因此在线程中独立,互不影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值