今天线程池实现,看到一个使用ThreadLocal的地方,研究了一下ThreadLocal这东西,发现很有意思。
从源码研究看ThreadLocal的实现原理吧
package com.sogou.game.cms.pool; import org.apache.thrift.transport.TSocket; public class ConnectionManager { ThreadLocal<TSocket> socketThreadSafe = new ThreadLocal<TSocket>(); /** 连接提供池 */ public ConnectionProvider connectionProvider; public ConnectionManager(){ connectionProvider=new ConnectionProviderImpl(); } /** * 取socket * @return TSocket */ public TSocket getSocket() { TSocket socket = null; try { socket = connectionProvider.getConnection(); socketThreadSafe.set(socket); return socketThreadSafe.get(); } catch (Exception e) { e.printStackTrace(); } finally { connectionProvider.returnCon(socket); socketThreadSafe.remove(); } return socket; } public ConnectionProvider getConnectionProvider() { return connectionProvider; } public void setConnectionProvider(ConnectionProvider connectionProvider) { this.connectionProvider = connectionProvider; } }
这段代码里面使用了ThreadLocal,ThreadLocal在使用时一般会声明为static变量,后面分析源码时候会说到为什么是static。
ThreadLocal
看一下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) return (T)e.value; } return setInitialValue(); }
获取当前线程,然后将当前线程传入getMap()得到ThreadLocalMap
下面是ThreadLocalMap的实现方式,可以简单认为是一个map,key为ThreadLocal值,value为要set的值;
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; } } }
继续getMap方法
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
返回Thread t的threadLocals的值,那threadLocals为何物呢?
ThreadLocal.ThreadLocalMap threadLocals = null;
转了一圈怎么又回来了
理一下思路
static ThreadLocal 在set的时候是set到Thread自有的ThreadLocalMap中,key为threadlocal变量
ThreadLocal的作用就了然了
在多线程,假设ThreadA、ThreadB,static的ThreadLocal是相同的,当ThreadA执行set方法是,是将相应的key、value set自己独有的ThreadLocalMap中,get方法的原理也同样。由于key不变,所以保证多线程在get、set时取到自身在set、get时值,这也是为什么ThreadLocal一般是static了。