今天线程池实现,看到一个使用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了。