ThreadLoacl类解析

来源:互联网 发布:域名ns记录查询 编辑:程序博客网 时间:2024/05/29 16:18

ThreadLocal 类的解析:

类继承关系
java.lang.Object
java.lang.ThreadLocal

官方描述:
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量。ThreadLocal 在类声明为private static作为类成员变量来使用。

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说无法获取到数据。Android的源码中Looper也用到了ThreadLocal。,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。
比如对于Handler来说,它需要获取当前线程的Looper,很显然Looper的作用域就是线程并且不同线程具有不同的Looper,这个时候通过ThreadLocal就可以实现Looper在线程中的存取,。

简单的例子:
类内部成员变量
private ThreadLocal threadLocal
= new ThreadLocal();
//主线程调用Set()
threadLocal.set(true);

Log.w(“Tag”, “mainThread:” + threadLocal.get());
new Thread(){
@Override
public void run() {
//子线程调用Set()
threadLocal.set(false);
Log.w(“Tag”, “childThread1:” + threadLocal.get());
}
}.start();

new Thread(){
@Override
public void run() {
//子线程直接取值,
Log.w(“Tag”, “childThread2:” + threadLocal.get());
}
}.start();

结果:这里写图片描述

可以看到,在不同线程中访问同一个ThreadLocal 对象,但是通过ThreadLocal取到的值是不一样的
主线程 和 第一个子线程,取得了各自set进去的对象的值,第二个子线程 因为没有值,获得null

成员

简单看下ThreadLocal类的组成,有set() ,get()方法
这里写图片描述

THreadLocal 有个内部类Values类。
这里写图片描述

Values是ThreadLocal的静态成员内部类, 这个类内部有个成员变量table,
类型为Object[],Values内部的方法add(),put(),..等方法其实就是在操作这张表。

而查看Thread类可以看到有个成员变量
这里写图片描述

可以知道Values的作用就是用来存储线程的ThreadLocal 数据

简单分析下ThreadLocal的set方法,
这里写图片描述

取到该线程的内部成员values, 调用put方法,

简单查看下Value的put方法

这里写图片描述

可以看出如果ThreadLocal的reference对象在table数组中的位置是index,那么THreadLocal的值在table数组中的索引就是index+1,最终的值也就保存在table[index+1]中了

现在,再看下ThreadLocal 类 get()方法的流程

1.获得当前的线程
2.根据当前的线程,获得线程的Thread.Values类型的成员
3.如果该values不为空,则以ThreadLocal 自身的引用作为key来在table中获取对应的值
4.如果values为空,以该线程为参数 初始化values, 以 ThreadLocal自身的引用作为key,默 认值null作为value,调用put方法保存一个默认值。返回该值

了解了ThreadLocal,再来看Looper 是如何实现 在每个线程中得到该线程对应的Looper

Looper类有个静态成员变量 ThreadLocal sThreadLocal

我们都知道android中 在非主线程默认是没有Looper的,需要先调用Looper.prepare(),
Prepare()调用了带参数的prepare(true)方法,在这个方法中,创建了Loop,并调用静态成员
sThreadLocal的set方法,将自身存入。

可以看到 如果多次调用,prepare()方法,将会抛出异常 Only one Looper may be ……

要获得该线程对应的Looper ,只要在该线程内调用

就可以取到了。

要取到主线程的Looper,在子线程内直接调用getMainLooper(),

sMainLooper这个成员变量是由系统初始化化的。系统通过调用prepareMainLooper() 初始化主线程的Looper,
文档中指明了这个方法用户永远不需要调用。

0 0
原创粉丝点击