在学习消息机制的时候,了解到了ThreadLocal这个类,在这里分享给大家,希望对大家有所帮助。
首先我们来看一组代码:
ThreadLocal<String> local1 = new ThreadLocal();
ThreadLocal<String> local2 = new ThreadLocal();
new Thread(){
@Override
public void run() {
local1.set("thread1");
Log.d("----thread1----" + local1.get());
Log.d("----thread1----" + local2.get());
}
}.start();
new Thread(){
@Override
public void run() {
local2.set("thread2");
Log.d("----thread2----" + local1.get());
Log.d("----thread2----" + local2.get());
}
}.start();
运行结果:!(https://img-blog.csdn.net/20160815174829834)
我们可以发现在第一个线程中分明执行了local1.set(),也能通过local1.get()获取到刚刚设置的值,但是在第二个线程中local1.get()取值却为null呢?
带着这个疑问我们来看一下ThreadLocal的get和set方法
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
在外界调用set()之后,首先会通过values方法获取当前线程中的ThreadLocal的数据,数据存储在当前
线程的localValues中,如果localValues为null,就对其进行初始化,再将值进行存储。接下来我们来看看存
储
void put(ThreadLocal<?> key, Object value) {
cleanUp();
int firstTombstone = -1;
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == key.reference) {
table[index + 1] = value;
return;
}
if (k == null) {
if (firstTombstone == -1) {
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
从这段代码中我们可以看出,key和value值在table数组中前后位的关系,注意这里是Values类中的方
法,也就是说对应的key、value值的存储是对对应线程localValues对象中table变量的操作。
接下来我们再来看一下get方法
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
get方法逻辑很清晰,取当前Thread中的localValues对象,如果为null则返回初始值(默认初始值为
null),当然初始方法是可以重写的,不为空则取出table找到对应ThreadLocal的value。
候,比如Looper。
个人觉得ThreadLocal类也为我们在解决实际问题中提供了一种思路,不以ThreadLocal为数据存储容器
而是以不同的作用域为存储容器,使用复杂度、项目耦合度都有所改善
有问题欢迎指正=。=