1 前言
今天在学习handler源码,发现了handlder中使用了ThreadLocal。不但如此,在开源框架EventBus中也使用了ThreadLocal,所以对这个ThreadLocal做了一个研究,这里做一个总结,为一下篇handler讲解打下基础。
2 什么是ThreadLocal
官网:实现一个线程本地的存储,也就是说,每个线程都有自己的局部变量。所有线程都共享一个ThreadLocal对象,但是每个线程在访问这些变量的时候能得到不同的值,每个线程可以更改这些变量并且不会影响其他的线程,并且支持null值。
简单来说:ThreadLocal里面存储一个变量,供多个线程来访问共享。但是每一个线程改变了这个变量并不会影响其他的线程中变量的值。这就是ThreadLocal的神奇所在,让我们赶紧来学习一下吧。
3 ThreadLocal API介绍
ThreadLocal的API很简单,常用的就4个方法,下面我们来介绍一下:
方法 | 介绍 |
get() | 和set()方法配合使用获取当前线程所对应的线程局部变量。 |
remove() | 将当前线程局部变量的值删除,目的是为了减少内存的占用,需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度 |
set(T value) | 和get()方法配合使用,设置当前线程的线程局部变量的值。也就是说只对当前线程设置,其他线程是获取不到该值的 |
initialValue() | 返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null |
值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。下面我们做一个例子来介绍一下它的使用。
4 ThreadLocal实战
下面我们做一下例子来深入理解一下:
4.1 代码
我们启用3个线程。每个线程利用for循环打印5个数据。注意,我们想要是结果是:它们之间互相不影响。代码如下
public class MainActivity extends AppCompatActivity {
private ThreadLocal<Integer>mThreadLocal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mThreadLocal = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
MyThread myThread1 = new MyThread("线程1");
MyThread myThread2 = new MyThread("线程2");
MyThread myThread3 = new MyThread("线程3");
myThread1.start();
myThread2.start();
myThread3.start();
}
private class MyThread extends Thread{
public MyThread(String name){
super(name);
}
@Override
public void run() {
super.run();
for(int i=0;i<5;i++){
Integer num = mThreadLocal.get();
Log.d("mystudy",this.getName()+":"+num);
mThreadLocal.set(++num);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
4.2结果
由图中可以看出,3个线程并没有相互影响,各自打印自己的。
5总结
虽然我们多个线程共享一个ThreadLocal中的变量,但是ThreadLocal会分别给每个线程一个变量的副本,导致多个线程之间互不影响。
6 结尾
好了就讲到这里吧,在技术上我依旧是个小渣渣,加油!勉励自己!