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 结尾

好了就讲到这里吧,在技术上我依旧是个小渣渣,加油!勉励自己!