不忘初心 砥砺前行, Tomorrow Is Another Day !

相关文章
  • 一. 线程管理之Thread基础
  • 二. 线程管理之线程池
  • 三. 线程管理之ThreadLocal
  • 四. 线程管理之Android中的多线程

本文概要:

  1. 认识ThreadLocal
  2. 了解ThreadLocal的实现原理

在Android系统源码中,多处用到了Threadlocal,如最熟悉的Handler中的Looper,其次还有属性动画中AnimationHandler、ActivityThread、AMS都有涉及到.接下来一起来认识与了解它.

一. 认识ThreadLocal

概念:线程内部的数据存储类,可以实现在不同线程具有不同数据副本.它的作用域仅限于当前当前线程,线程之间互不干扰.

基本使用

这里定义了一个ThreadLocal用来存储Integer类型的数据,设置了默认值为999.分别在MainThread,SubThreadA对ThreadLocal的值进行设置,SubThreadB未进行设置值.

示例源码

public class ThreadLocalActivity extends AppCompatActivity {private static final String TAG = "ThreadLocalActivity";private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){@Overrideprotected Integer initialValue() {return 999;}};public static void startActivity(Context pkgContext) {Intent intent = new Intent(pkgContext, ThreadLocalActivity.class);pkgContext.startActivity(intent);}@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_threadlocal);threadLocal.set(100);new SubThreadA("SubThreadA").start();new SubThreadB("SubThreadB").start();System.out.println("MainThread:" + threadLocal.get());}class SubThreadA extends Thread {public SubThreadA(String name) {super(name);}@Overridepublic void run() {threadLocal.set(110);int value = threadLocal.get();System.out.println("SubThreadA:" + value);}}class SubThreadB extends Thread {public SubThreadB(String name) {super(name);}@Overridepublic void run() {int value = threadLocal.get();System.out.println("SubThreadB:" + value);}}}//调用输出
I: SubThreadA:110
I: MainThread:100
I: SubThreadB:999复制代码

最后通过调用输出结果,可以清晰的看到虽然操作的是同一个ThreadLocal对象,但是在三个不同线程存储的值是互不影响的.回过头再对照看概念性内容就清晰明了许多.另外在SubThreadB因为没有设置值,所以获得的是我们初始化设置的默认值999.

二. 了解ThreadLocal的实现原理

认识了它基本使用,接着一起来了解ThreadLocal的基本原理,之所以用了解,因为笔者自己对ThreadLocal的理解有限且实际开发中运用较少.这里就简单的看下原理.

2.1 当调用Set方法进行存储值时.

对应源码

public void set(T value) {Thread t = Thread.currentThread();//获取当前线程的ThreadLocalMapThreadLocalMap map = getMap(t);if (map != null)//不为空,直接存储值map.set(this, value);else//为空,创建一个ThreadLocalMap并存储值.createMap(t, value);}
复制代码

从上面源码可以看出,我们设置的值,是存储在ThreadLocalMap下的.当第一次存储时,先会createMap初始化一个ThreadLocalMap.接着看如何进行初始化的.

对应源码

void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);//将新值存储在table数组中,该数组类型是Entry,扩展了弱引用封装了ThreadLocal与value.table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);
}
复制代码

通过以上源码,可以很清楚的发现最终我们设置的值,是存储在一个Entry类型的table数组中的,这个Entry封装了ThreadLocal与Value.

接着,如果不是第一次set值,那么会进入ThreadLocalMap的set方法,我们继续往下看.

private void set(ThreadLocal<?> key, Object value) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();if (k == key) {//替换存在的值e.value = value;return;}if (k == null) {replaceStaleEntry(key, value, i);return;}}//将值存储在table数组中tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();}
复制代码

这里不分析具体算法,从上面可以发现最终也是保存在table数组中.

2.2 当调用Get方法获取存储值时.

对应源码

public T get() {Thread t = Thread.currentThread();//同样获取当前线程的ThreadLocalMapThreadLocalMap map = getMap(t);if (map != null) {//不为空,获取对应值ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}//为空,返回设置的默认值return setInitialValue();
}
复制代码

通过以上源码,get方法简单来说就是从当前线程的ThreadLocalMap对象中获取存储的值.

通过SET与GET源码简单分析,我们知道它们所操作的对象都是当前线程的ThreadLolocalMap对象的table数组,因此在不同线程中访问同一个ThreadLocal的set和get方法,它们对ThreadLocal所做的读写操作仅限于各自线程的内部.

本文小结

最后我们对ThreadLocal的实现流程做一个小结.

  1. Set方法时,将值存储在当前线程的ThreadLolocalMap对象的table数组中.

    • 该table数组是Entry类型,封装了ThreadLocal与Value.
  2. Get方法时,从当前线程的ThreadLolocalMap对象的table数组中获取存储的值.

最后奉上一个极简版的ThreadLocal的工作流程图.

ThreadLocal工作流程极简图

由于本人技术有限,如有错误的地方,麻烦大家给我提出来,本人不胜感激,大家一起学习进步.

参考链接:

  • www.cnblogs.com/whoislcj/p/…

三. 线程管理之ThreadLocal相关推荐

  1. 二. 线程管理之线程池

    不忘初心 砥砺前行, Tomorrow Is Another Day ! 相关文章 一. 线程管理之Thread基础 二. 线程管理之线程池 三. 线程管理之ThreadLocal 四. 线程管理之A ...

  2. Android线程管理(一)

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  3. 详解线程本地变量ThreadLocal

    并发应用的一个关键地方就是共享数据.如果你创建一个类对象,实现Runnable接口,然后多个Thread对象使用同样的Runnable对象,全部的线程都共享同样的属性.这意味着,如果你在一个线程里改变 ...

  4. rtems线程管理与调度(一)

    rtemsahi一个以线程为基本调度单位的实施操作系统,调度算法是基于优先级的抢占式线程调度,支持256个线程优先级,0代表最高优先级,主要用于内部线程,255是最低线程,是空闲线程的优先级,用户线程 ...

  5. [转]C++ 11 多线程--线程管理

    转载地址:https://www.cnblogs.com/wangguchangqing/p/6134635.html 说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并 ...

  6. 并发基础(十) 线程局部副本ThreadLocal之正解

    什么是ThreadLocal ThreadLocal是线程局部变量,所谓的线程局部变量,就是仅仅只能被本线程访问,不能在线程之间进行共享访问的变量.在各个Java web的各种框架中ThreadLoc ...

  7. C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  8. C++多线程并发中线程管理

    一.何为并发 刚开始接触计算机编程语言时,我们编写一个程序,在main入口函数中调用其它的函数,计算机按我们设定的调用逻辑来执行指令获得结果.如果我们想在程序中完成多个任务,可以将每个任务实现为一个函 ...

  9. 线程管理(九)使用本地线程变量

    声明:本文是< Java 7 Concurrency Cookbook >的第一章, 作者: Javier Fernández González 译者:郑玉婷 校对:方腾飞 使用本地线程变 ...

最新文章

  1. Python踩坑指南(第二季)
  2. akae-arm9异常
  3. C++ Primer 5th笔记(chap 15 OOP)继承中的类作用域
  4. Robot Framework操作MySQL数据库和Oracle数据库
  5. 4位加法器的设计代码verilog_HDLBits:在线学习Verilog(六 · Problem 25-29)
  6. vim反向删除_VIM之操纵缓冲区列表
  7. 高效 Java Web 开发框架 JessMA v3.2.1 正式发布
  8. 讯飞C/C++语音合成基础篇
  9. SpringBoot总结之浅析自动化配置原理
  10. flexsim怎么设置传送带方向_Flexsim仿真教程学习(六)-分拣系统
  11. 飞天侠淘宝客源码8.0终结版仿卷皮模板-免费开源
  12. Spring学习04:事务控制(TransactionManager)
  13. 程序员容易发福的原因及解决办法
  14. 智能车基于RT1064+无线串口透传模块利用MATLAB辅助调节PID参数
  15. 【贪心法】黑白连线问题
  16. 思维导图带你了解22个职场学习网站!亲测好用
  17. w ndows10图标,win10桌面图标变白怎么解决
  18. 管道pipe-有名管道
  19. 在 Android 设备上搭建 Web 服务器
  20. 江苏省发布大数据引领推动融合发展专项行动计划

热门文章

  1. 使用 GDB 恢复堆栈信息
  2. C/C++:Windows编程—创建进程、终止进程、枚举进程、枚举线程、枚举DLL
  3. XAF-BI.Dashboard模块概述 web/win
  4. H3C DHCP服务器显示及维护
  5. Python-----规范化开发
  6. [leetcode]687. Longest Univalue Path
  7. 【CUDA开发】 Check failed: error == cudaSuccess (8 vs. 0) invalid device function
  8. html、css、js实现简易计算器
  9. mysql导出csv格式去除字段中的\n\r
  10. YY:马化腾的大漏招