最近查看Android,Looper源码的时候,看到一个这样的写法
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
给我的第一印象是:
1.比较懒的一种单例的写法。
2.跟线程有很大的关系。不然怎么会叫做ThreadLocal呢?
3.觉得是一种集合,因为提供了get/set方法。 但是本身是单例,那么get出来不是同一个值吗?那不就是没有意义了吗?带着这些问题查看了一下源码。
public class ThreadLocal<T> {
/* Thanks to Josh Bloch and Doug Lea for code reviews and impl advice. */
/**
* Creates a new thread-local variable.
*/
public ThreadLocal() {}
/**
* Returns the value of this variable for the current thread. If an entry
* doesn't yet exist for this variable on this thread, this method will
* create an entry, populating the value with the result of
* {@link #initialValue()}.
*
* @return the current value of the variable for the calling thread.
*/
@SuppressWarnings("unchecked")
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);
}
/**
* Provides the initial value of this variable for the current thread.
* The default implementation returns {@code null}.
*
* @return the initial value of the variable.
*/
protected T initialValue() {
return null;
}
/**
* Sets the value of this variable for the current thread. If set to
* {@code null}, the value will be set to null and the underlying entry will
* still be present.
*
* @param value the new value of the variable for the caller thread.
*/
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
/**
* Removes the entry for this variable in the current thread. If this call
* is followed by a {@link #get()} before a {@link #set},
* {@code #get()} will call {@link #initialValue()} and create a new
* entry with the resulting value.
*
* @since 1.5
*/
public void remove() {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
values.remove(this);
}
}
/**
* Creates Values instance for this thread and variable type.
*/
Values initializeValues(Thread current) {
return current.localValues = new Values();
}
/**
* Gets Values instance for this thread and variable type.
*/
Values values(Thread current) {
return current.localValues;
}
/** Weak reference to this thread local instance. */
private final Reference<ThreadLocal<T>> reference
= new WeakReference<ThreadLocal<T>>(this);
/** Hash counter. */
private static AtomicInteger hashCounter = new AtomicInteger(0);
/**
* Internal hash. We deliberately don't bother with #hashCode().
* Hashes must be even. This ensures that the result of
* (hash & (table.length - 1)) points to a key and not a value.
*
* We increment by Doug Lea's Magic Number(TM) (*2 since keys are in
* every other bucket) to help prevent clustering.
*/
private final int hash = hashCounter.getAndAdd(0x61c88647 * 2);
/**
* Per-thread map of ThreadLocal instances to values.
*/
代码比较多,但是我们挑比较关键的地方看( set/get)
get:获取当前线程的localValues,如果是null的话,initializeValues一个localValues。然后从localValues中获取值。
set:获取当前线程的localValues,如果是null的话,initializeValues一个localValues。然后把值放入当前线程中。
- ThreadLocal本身并没有存储数据的能力,真正存储数据的地方是存储在当前线程中。
- 每一个线程localValues是不同的。