定义

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,存储以后,只能在该线程中可以获取到存储的数据,对于其他线程来说无法获取。

使用场景

  1. 某些数据以线程为作用域并且在不同线程有不同的数据时。比如每个线程要使用Handler需要创建Looper,而且每个线程的Looper是不同的,所以使用ThreadLocal可以轻松的实现Looper在线程中的存取。
  2. 复杂逻辑下的对象传递。比如线程中的一个监听器,它需要贯穿线程的整个生命周期,这时就可以使用ThreadLocal让监听器作为线程中的全局变量而存在。

工作原理

ThreadLocal是一个泛型类,它的定义是public class ThreadLocal< T >,只要弄清楚它的get和set方法就能明白它的工作原理。

set方法的源码:

 /**
* 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);
}

通过调用values方法

Values values(Thread current) {
return current.localValues;
}

来得到存在Thread类里的localValues,然后调用put方法把ThreadLocal的值存储起来:

/**
* Sets entry for given ThreadLocal to given value, creating an
* entry if necessary.
*/

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;
}
}
}

由源码可知,ThreadLocal的值是存在Values的一个内部数组table里,并且存储位置是在ThreadLocal的reference对象的存储位置的下一个位置。也就是说,ThreadLocal的reference对象和值都会存储到table数组里,如果reference的位置是index,那么值的位置索引就是index+1。


get方法的源码:

/**
* 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);
}

由源码可知,去get值时,是先找到reference的索引位置,然后再加1去得到值。如果找不到当前线程的Values,那么就返回initializeValues的值,这个方法我们可以自己覆盖:

 /**
* Creates Values instance for this thread and variable type.
*/

Values initializeValues(Thread current) {
return current.localValues = new Values();
}

demo

public class MainActivity extends ActionBarActivity {

private static final String TAG = "ThreadLocal";

private ThreadLocal<Integer> mThreadLocal = new ThreadLocal<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mThreadLocal.set(7);
Log.d(TAG, "In Main Thread: " + mThreadLocal.get());

new Thread(){
@Override
public void run() {
mThreadLocal.set(6);
Log.d(TAG, "In Sub Thread 1: " + mThreadLocal.get());
}
}.start();

new Thread(){
@Override
public void run() {
Log.d(TAG, "In Sub Thread 2: " + mThreadLocal.get());
}
}.start();
}

}

输出的log为:

D/ThreadLocal﹕ In Main Thread: 7
D/ThreadLocal﹕ In Sub Thread 1: 6
D/ThreadLocal﹕ In Sub Thread 2: null

由于子线程2并没有设置mThreadLocal的值,所以get得到的是null。
由此验证了同一个ThreadLocal对象在各个线程间存储的值互不干扰,因为每一个线程有自己的ThreadLocal.Values。

更多相关文章

  1. java基础---多线程---java内存模型
  2. java 使用Callable和Future返回线程执行的结果
  3. Java多线程聊天对话框
  4. Android 多线程下载文件原理霸气解析介绍 (完结版)-----greendao
  5. Java多线程六:线程优先级和yield()让步函数
  6. java多线程爬虫
  7. javafx 和netty 混合使用出现线程不一致问题,求大神指点
  8. Java多线程之Thread、Runnable、Callable及线程池
  9. Java,Socket&TCP编程 实现多线程端对端通信与文件传输

随机推荐

  1. Android(安卓)EditText 属性汇总
  2. Android实用编程技巧代码总结
  3. 自定义view-制作一个加载中的圆形
  4. android 对话框详解
  5. Android(安卓)签名信息读取
  6. android之RecycleView之ItemTouchHelper
  7. Android WiFi 架构总览(模块及接口)
  8. ionic build android log
  9. 播放音乐时的状态条使用
  10. Android AD Manifest