Android 线程本地变量<一> ThreadLocal源码解析
来源:互联网 发布:游戏原画网络班 编辑:程序博客网 时间:2024/06/05 16:50
Android 线程本地变量<一> ThreadLocal源码解析
@(Android系统源码解析)[Android, ThreadLocal]
声明:转载请注明出处,知识有限,如有错误,请多多交流指正!
- Android 线程本地变量一 ThreadLocal源码解析
- ThreadLocal定义和作用
- ThreadLocal代码使用
- ThreadLocal源码解析
注:基于Android 6.0(API 23)源码
为保证多个线程对共享变量的安全访问,通常会使用synchronized来保证同一时刻只有一个线程对共享变量进行操作。这种情况下可以将类变量放到ThreadLocal类型的对象中,使变量在每个线程中都有独立拷贝,不会出现一个线程读取变量时而被另一个线程修改的现象
ThreadLocal定义和作用
1. 什么是ThreadLocal ?
JDK 1.6文档是这样定义的:
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
2. ThreadLocal的作用
每个线程都有自己的局部变量,一个线程的本地变量对其他线程是不可见的,ThreadLocal 不是用于解决共享变量的问题的,不是为了协调线程同步而存在,而是为了方便每个线程处理自己的状态而引入的一个机制
ThreadLocal代码使用
同时开辟四个线程,操作一个数据
用Map
存储的时候,线程并发访问,数据都不同
private static Map<Integer, Integer> map = new HashMap<>(); private static void test2() { for (int i = 0; i < 4; i++) { new Thread(new Runnable() { @Override public void run() { int n = 0; if (map.get(0) != null) { n = map.get(0); } for (int j = 0; j < 5; j++) { n++; } map.put(0, n); System.out.println(Thread.currentThread().getName() + "-->" + map.get(0)); } }, "Thread-Map-" + i).start(); } }
运行结果
Thread-Map-1–>5
Thread-Map-2–>10
Thread-Map-0–>15
Thread-Map-3–>20
用ThreadLocal
存储数据,每个数据都是独立的,线程之间没有任何干扰
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); private static void test() { for (int i = 0; i < 4; i++) { new Thread(new Runnable() { @Override public void run() { int n = 0; if (threadLocal.get() != null) { n = threadLocal.get(); } for (int j = 0; j < 5; j++) { n++; } threadLocal.set(n); System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get()); } }, "Thread-" + i).start(); } }
运行结果
Thread-1–>5
Thread-0–>5
Thread-2–>5
Thread-3–>5
那么ThreadLocal
是如何关联线程的呢?可以看一看源码
ThreadLocal源码解析
注意:在Android中,ThreadLocal像是对原来的Java中的ThreadLcal做了优化的实现
1. ThreadLocal的结构
可以直观地看到在android中ThreadLocal
类提供了一些方法和一个静态内部类Values
,其中Values
主要是用来保存线程的变量的一个类,它相当于一个容器,存储保存进来的变量
2. ThreadLocal的内部实现
成员变量
/** Weak reference to this thread local instance. */ private final Reference<ThreadLocal<T>> reference= new WeakReference<ThreadLocal<T>>(this);
通过弱引用存储ThreadLocal本身,主要是防止线程自身所带的数据都无法释放,避免OOM
private static AtomicInteger hashCounter = new AtomicInteger(0);private final int hash = hashCounter.getAndAdd(0x61c88647 * 2);
hashCounter
是线程安全的加减操作,getAndSet(int newValue)
取当前的值,并设置新的值;而0x61c88647 * 2作用是:
在Value
存在数据的主要存储数组table上,而table被设计为下标为0,2,4…2n的位置存放key,而1,3,5…(2n +1 )的位置存放value,`0x61c88647 * 2
保证了其二进制中最低位为0,也就是在计算key的下标时,一定是偶数位
方法
- public T get():返回此线程局部变量的当前线程副本中的值
public T get() { // Optimized for the fast path. // 获取当前线程 Thread currentThread = Thread.currentThread(); // 获取当前线程的Value实例 Values values = values(currentThread); if (values != null) { Object[] table = values.table; // 如果键值的key的索引为index,则所对应到的value索引为index+1. // 由此分析可知 hash&values.mask 获取的就是key的索引值 int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { // 如果当前Value实例为空,则创建一个Value实例 values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); }
可以看出get()
是通过value.table这个数组通过索引值来找到值得,
initializeValues(currentThread)
主要是直接new
出一个新的Values
对象
Values initializeValues(Thread current) { return current.localValues = new Values(); }
- protected T initialValue() 返回此线程局部变量的当前线程的“初始值”。
protected T initialValue() { return null; }
也就是默认值为Null
,当没有设置数据的时候,调用get()
的时候,就返回Null
;可以在创建ThreadLocal
的时候复写initialValue()
方法可以定义初始值
- public void set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值.
public void set(T value) { // 获取当前线程 Thread currentThread = Thread.currentThread(); // 获取当前线程的Value实例 Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } // 将数据设置到Value中 values.put(this, value); }
- public void remove() 移除此线程局部变量当前线程的值。
- Values values(Thread current) 通过线程获取Values对象。
Values内部存储数据,请看Android 线程本地变量<二> ThreadLocal Values源码解析
博客
- Android 线程本地变量<一> ThreadLocal源码解析
- Android 线程本地变量<二> ThreadLocal Values源码解析
- ThreadLocal---线程本地变量
- ThreadLocal---线程本地变量
- ThreadLocal,线程本地变量
- 线程本地变量ThreadLocal
- ThreadLocal线程本地变量
- ThreadLocal 线程本地变量
- 线程本地变量ThreadLocal
- 线程本地变量ThreadLocal
- 【Android应用源码分析】Java多线程:线程本地变量ThreadLocal源码分析
- ThreadLocal线程本地变量的超详细解析
- Java线程(篇外篇):线程本地变量ThreadLocal
- Java线程(篇外篇):线程本地变量ThreadLocal
- Java线程(篇外篇):线程本地变量ThreadLocal
- Java线程(篇外篇):线程本地变量ThreadLocal
- Java线程(篇外篇):线程本地变量ThreadLocal
- Java线程(篇外篇):线程本地变量ThreadLocal
- 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (HDU_2191) 多重背包 + 二进制思想优化
- 打造统一第三方SDK接入框架(用户模块,支付模块,发享模块)(一)
- 11.2 Job Seperation causes WARNINGS and ORA-15025 ORA-27041 With Certain Users (文档 ID 1317692.1)
- 对jsp九大内置对象的理解
- RTMP直播点播-基于开源crtmpserver
- Android 线程本地变量<一> ThreadLocal源码解析
- Android 深入理解Android中的自定义属性
- 59.View the Exhibit and examine the data in the PRODUCTS table.
- NEUOJ 1681
- win10 Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host
- 二级指针和二维数组详解
- 图片 音频等文件转成base64编码
- HTML5新特性
- SVM入门(八)松弛变量