在源码中很多地方都会用到ThreadLocal,它可在在指定的线程中存储和取出数据,同一个变量在不同的线程中取得值只会是对应线程得值,打个比方说在Looper中的loop()方法中
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
这个方法第一句就是 final Looper me = myLooper();
public static Looper myLooper() {
return sThreadLocal.get();
}
这个方法其实就是通过ThreadLocal来获取当前线程的Looper对象,有get必然有set的地方
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
/// M: ALPS00297986
if (!IS_USER_BUILD) {
long instances = VMDebug.countInstancesOfClass(Looper.class, false);
在我们调用Looper.prepare()时就会执行这个set操作,现在就来看看ThreadLocal的工作原理,是怎么实现按照线程来存储值得
ThreadLocal.set
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
Values values(Thread current) {
return current.localValues;
}
这个方法看上去就几行代码,其中Values 是ThreadLocal的静态内部类
,通过values()方法获取当前线程的ThreadLocal.Values,如果没有就会去实现这个,然后通过put()方法将值存进去
void put(ThreadLocal<?> key, Object value) {
cleanUp();
// Keep track of first tombstone. That's where we want to go back
// and add an entry if necessary.
int firstTombstone = -1;
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == key.reference) {
// Replace existing entry.
table[index + 1] = value;
return;
}
if (k == null) {
if (firstTombstone == -1) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
// Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
在代码中可以看到我们的value不管在什么情况下都是存放在 key.reference的下一位的,而这个key则使用的弱引用
/** Weak reference to this thread local instance. */
private final Reference<ThreadLocal<T>> reference
= new WeakReference<ThreadLocal<T>>(this);
这里为什么要使用弱引用呢,应该是防止内存泄漏做的优化,当key指向的对象不存在时在系统gc时这个key也自然被回收,在我们执行set,remove等操作时也会通过cleanUp()方法对ThreadLocal做一次清理,会处理掉一些不用的。
在使用LocalThread的时候如果某个ThreadLocal对象我们不用了,还是remove掉比较好,不然有些强引用还是会导致内存泄漏的,比如我们定义了一个static的ThreadLocal如果不remove还是有可能会导致内存泄漏的
关于不同的引用我们需要根据自己的需求选择,这在很大程度上能避免一些内存泄漏的问题,
强引用:普通的引用,强引用指向的对象不会被回收;
软引用:仅有软引用指向的对象,只有发生gc且内存不足,才会被回收;SoftReference
弱引用:仅有弱引用指向的对象,只要发生gc就会被回收。WeakReference