ThreadLocal 的含义是线程的本地变量,每个线程都有一个自己管理的独立的引用变量,这个其实就是个map(ThreadLocalMap)这个后面说
这个主要作用在:在多线程中,而且每个线程都要有同样的初始值,但是每个线程的本地值,只能自己才能修改,其他线程不可以改,具有独立性
真正保存数据的是ThreadLoacalMap来做的,ThreadLocal只是个操作工具而已
举个例子:在Android的Looper中,为了让每个线程都有一个Looper,就是用的这个实现的ThreadLocal,
二、结构图 三、详细分析 1、例子ThreadLocallocalString=new ThreadLocal () { @Nullable @Override protected String initialValue() { return "init"; } }; Thread thread2= new Thread(new Runnable() { @Override public void run() { Log.i("localmm","local2:"+localString.get()); } }); Thread thread1= new Thread(new Runnable() { @Override public void run() { Log.i("localmm","local1:"+localString.get()); localString.remove(); Log.i("localmm","local1:"+localString.get()); localString.set("init2"); Log.i("localmm","local1:"+localString.get()); } }); thread1.start(); thread2.start();
上面这个例子实例化了一个LocalThread 线程在调用这个对象的时候 都可以拷贝一个它的值的副本
然后自己操作自己的数据
2、分析那么我们看下在Thread中第一次调用了localString.get() 里面做了什么
public T get() {
//获取当前的线程,这里获取的就是上面的Thread1
Thread t = Thread.currentThread();
//第一次,这个时候我们获得的map是null的
ThreadLocalMap map = getMap(t);
if (map != null) {
//如果有 就从这个map中取出来
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//第一次会走到这里来
return setInitialValue();
}
//这个是获取的线程中的内部属性threadLocals
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
上图可以看到每个线程内部都有一个ThreadLocalMap属性,默认是null的
继续我们来看下setInitialValue()
private T setInitialValue() {
//这个是需要在初始化LocalThread时候实现的
T value = initialValue();
Thread t = Thread.currentThread();
//第一次获得的map=null
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//如果是空就床架一个然后设置到Thread里面threadLcoals变量中
createMap(t, value);
return value;
}
void createMap(Thread t, T firstValue) {
//创建一个ThreadLocalMap 并且赋值
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
上面这个是get的过程,我们可以看出来 其实每个Thread里面都一个threadLocals的变量 这个是一个Map结构的变量(ThreadLocalMap),这个ThreadLocalMap是ThreadLocal的内部静态类,而且这个map不是用的系统的map是自己实现的,我们来看下
static class ThreadLocalMap {
static class Entry extends WeakReference> {
Object value;
Entry(ThreadLocal> k, Object v) {
super(k);
value = v;
}
}
private static final int INITIAL_CAPACITY = 16;
private Entry[] table;
private int size = 0;
private Entry getEntry(ThreadLocal> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
}
ThreadLocalMap 里面有个Entry 这个entry的可以是ThreadLocal value就是保存的数据
原来在ThreadLocal 有一个threadLocalHashCode来计算map中的索引位置的具体是:
int i = key.threadLocalHashCode & (table.length - 1);
所以一个线程里面里面的threadLocalMap,可以保存很多的[ThreadLocal,Object]键值对
这个map还实现了自己扩容,索引的散列化,等
ThreadLocal里面的set和get逻辑类似,都是去每个线程的threadLocals里去操作map数据,大家可以自己去看



