ThreadLocal
定义
为每一个线程提供变量的副本,实现了线程的隔离,也可以保证线程的安全性。
和ThreadLocal相关类
- ThreadLocal内部类ThreadLocalMap
- ThreadLocalMap.Entry ThreadLocalMap内部类
- Thread类
ThreadLocal是一个带泛型的类
public class ThreadLocal<T> {}
源码分析
Android中最典型用到ThreadLocal地方在Looper里
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void loop() {
final Looper me = myLooper();
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
}
sThreadLocal.get();源码解析
//泛型T为Looper,我们都会把T 替换成Looper
public class ThreadLocal<Looper> {
public Looper get() {
Thread t = Thread.currentThread();
//第一步: 通过getMap(t)获取一个ThreadLocalMap
ThreadLocalMap map = getMap(t);
//第一次进来这个map肯定为null
if (map != null) {
//ThreadLocalMap.getEntry,获取缓存
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
Looper result = (Looper)e.value;
return result;
}
}
//第三步 创建一个Looper
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
//第二步: 返回的是当前线程里的一个成员变量ThreadLocalMap threadLocals
return t.threadLocals;
}
private Looper setInitialValue() {
//第四步:通过initialValue()api得到了一个Looper 而initialValue()方法直接return 了一个null
//所这在没有做调用其它api的情况下ThreadLocal.get()方法获取的值为null
Looper value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//第五步: 创建ThreadLocalMap ,将Thread 里的成员变量threadLocals 附值
//threadLocals = new ThreadLocalMap(this, firstValue);this为ThreadLoca, firstValue第一次为null
//这个时候当前线程的threadLocals就不为null了
createMap(t, value);
return value;
}
protected Looper initialValue() {
return null;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
}
class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
}
//再来分析Looper里是怎么将sThreadLocal里设置值的
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//第六步: 调用sThreadLocal.set方法将新创建的Looper给设置进去
sThreadLocal.set(new Looper(quitAllowed));
}
//第九步:当set完值的时候再去get这就完全不一样了。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public Looper get() {
Thread t = Thread.currentThread();
//以当前线程为key去找值,获取的是当前线程的成员变量threadLocals,这个时候也不为null。且是每个Thread类独有的
ThreadLocalMap map = getMap(t);
//这个时候map不为null了,已经有值了
if (map != null) {
//第十步:当set完值的时候再去get这就完全不一样了。
//ThreadLocalMap.getEntry,获取缓存 ThreadLocalMap其实相当于一个这样的HashMap<Thread,Looper>
//ThreadLocalMap.Entry 是一个WeakReference<ThreadLocal<Looepr>>
//ThreadLocalMap里有个成功变量Entry[] table他会保存很多Entry
//每个ThreadLocalMap.Entry又执有了不同的ThreadLocal 和泛型T(Looper)类
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
Looper result = (Looper)e.value;
return result;
}
}
//第三步 创建一个Looper
return setInitialValue();
}
}
public class ThreadLocal<Looper> {
public void set(Looper value) {
Thread t = Thread.currentThread();
//第七步: 通过getMap获取当前线程的ThreadLocalMap ,如果在set之前什么没有调用ThreadLocal里的get方法那么这个map就为null
//如果在set之前调用了get方法,那么这个map就不为null
ThreadLocalMap map = getMap(t);
if (map != null)
//第八步: 将传进来的Looper给设置进来了,key为ThreadLocal也主是Looper里的成功变量sThreadLocal valus为创建的Looper
map.set(this, value);
else
//第五步: 创建ThreadLocalMap ,将Thread 里的成员变量threadLocals 附值
//threadLocals = new ThreadLocalMap(this, firstValue);this为ThreadLocal, firstValue这个时候为value 不为null了
//这个时候当前线程的threadLocals就不为null了
createMap(t, value);
}
}
总结
1:每一个Thread都执有一个ThreadLocalMap变量threadLocals 他是通过ThreadLocal的createMap()方法创建
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
2:ThreadLocalMap是ThreadLocal的一个内部类,他相当于一个HashMap<ThreadLocal,Object>,以ThreadLocal为Key,所以这里可以保证每一个ThreadLocal只能有一个值
3:而每一个Thread都执有一个ThreadLocalMap变量所以每一个线程里只要传入的ThreadLocal不变获取到的值也是唯一的。
4:ThreadLocalMap里有一个内部类 Entry
5:Entry这个类他会执行一个ThreadLocal和传进来的Object
6:ThreadLoca.get()先是获取本线程的一个ThreadLocalMap,然后通过ThreadLocalMap的getEntry方法找到值
Threadlocal类提供set和get方法,
每一个Thread内执有一个ThreadLocalMap成员变量
ThreadLocalMap有一个Entry[] table成员变量
Threadlocal的get方法
如果之前没有调用过set或者get那么会通过setInitialValue方法为当前Thread里的成员变量threadLocals(ThreadLocalMap)赋值,初始化ThreadLocalMap时,会为其内部成功变量table初始化,并将传入的Threadlocal当作key,null当作value当作第一个数组元素
如果之前调用过set或者get 那么threadLocals(ThreadLocalMap)不为null,会通过threadLocals的getEntry方法获取到传入的Threadlocal对应的Entry值,再获取Entry的value就拿到了想要的
Threadlocal的set方法
如果之前没有调用过set或者get则会通过createMap方法为当前Thread的成员变量threadLocals(ThreadLocalMap)赋值,初始化ThreadLocalMap时,会为其内部成功变量table初始化,并将传入的Threadlocal当作key,传入的value当作第一个数组元素
如果之前调用过set或者get 那么当前Thread的threadLocals(ThreadLocalMap)有值,则直接调用ThreadLocalMap的set方法赋值
ThreadLocalMap的set方法则会寻找传过来的Threadlocal并找到对应的值再替换
示例
public class ThreadLocalTest {
public static void main (String [] args) {
ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 1;
}
};
new Thread(() -> {
Integer integer = threadLocal.get();
threadLocal.set(integer + 4);
System.out.println("threadLocal1111: " + threadLocal.get());
}).start();
new Thread(() -> {
System.out.println("threadLocal22222: " + threadLocal.get());
}).start();
new Thread(() -> {
System.out.println("threadLocal33333 before: " + threadLocal.get());
threadLocal.set(9);
System.out.println("threadLocal33333 after :" + threadLocal.get());
}).start();
}
日志输出如下:
System.out: threadLocal1111: 5
System.out: threadLocal22222: 1
System.out: threadLocal33333 before: 1
System.out: threadLocal33333 after :9
每一个线程 threadLocal都是不同的,他们也是隔离的,在一个线程设置值对其它线程是没有影响的
}