目录

  • 背景
  • ThreadLocal的作用
  • ThreadLocal特性
  • ThreadLocal实现
    • 1. T get()
    • 2. set(T value)
    • 3. remove()
  • 验证
    • 一个对象只存一个数据
    • 多少个对象就能存多少个数据

背景

这两天稍微有点空,在追溯之前的android 7.0之前的手机用View.post 出现不执行的问题时,结识了ThreadLocal,且问题的原因也是系统内部使用ThreadLocal造成的。因此记录并分享之。
关于view.post不执行的坑点

ThreadLocal的作用

ThreadLocal的作用主要是做数据隔离,填充的数据(对象)只属于当前线程,变量的数据对别的线程而言是相对隔离的,在多线程环境下,一个线程防止自己的变量被其它线程篡改。1
A线程存了一个对象objectA,此时B线程通过同一个ThreadLocal对象去取的话是取不到objectA的。

通俗的讲:
A、B钱包都没钱了,A从银行取了1000 人民币,装入了自己的钱包,B去商店买1000的商品,此时B从自己钱包里面拿钱时,钱包是空的。
AB好比是线程,存的数据就是1000人民币,消费的时候只能从自己钱包拿出来,只是A和B存到钱包的过程可以通过ThreadLocal来完成的。

ThreadLocal特性

ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题,不同的点是2

  1. Synchronized是通过线程等待,牺牲时间来解决访问冲突
  2. ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。

ThreadLocal实现

ThreadLocal 对外一共提供了get、set和remove的函数,这里请注意set和get不是一般bean的get和set。而且巧妙的使用了调用栈关系,并取了当前调用的线程来做一些列的处理,所以与线程密切相关。调用线程指的是执行get、set、和remove的线程。

1. T get()

 public T get() {// Optimized for the fast path.Thread currentThread = Thread.currentThread();Values values = values(currentThread);if (values != null) {Object[] table = values.table;int index = hash & values.mask;if (this.reference == table[index]) {return (T) table[index + 1];}} else {values = initializeValues(currentThread);}return (T) values.getAfterMiss(this);}

2. set(T value)

/*** Sets the value of this variable for the current thread. If set to* {@code null}, the value will be set to null and the underlying entry will* still be present.** @param value the new value of the variable for the caller thread.*/public void set(T value) {Thread currentThread = Thread.currentThread();Values values = values(currentThread);if (values == null) {values = initializeValues(currentThread);}values.put(this, value);}

3. remove()

 /*** Removes the entry for this variable in the current thread. If this call* is followed by a {@link #get()} before a {@link #set},* {@code #get()} will call {@link #initialValue()} and create a new* entry with the resulting value.** @since 1.5*/
public void remove() {Thread currentThread = Thread.currentThread();Values values = values(currentThread);if (values != null) {values.remove(this);}}
Values values(Thread current) {return current.localValues;
}

从get/set/remove实现中能看出,都是取当前线程,再从当前线程中拿出values,从values取出或put。而这个values是属于Thread的莫不是ThreadLocal的,这点要注意一下。value内部包含了数组,那么程序存取的数据对象就是放到这个数组中的,并且是以hash进行映射,和HashMap的实现不一样,思想几乎一样。

验证

接下来需要代码实际演示一下,不然死不了心。那么问题来了,从get和set来看都只有一个value参数,假如要set多个怎么办,而且set又是以ThreadLocal对象作为key去“存储”的。不要慌,既然是以ThreadLocal对象作为key,那就多创建几个ThreadLocal对象,多个对象被一个线程调用,那么多个数据就被存到了同一个线程的存储区(table)中。

一个对象只存一个数据

static void testThreadLoacal() {final ThreadLocal<String> threadLocal = new ThreadLocal<>();String str = "Test ThreadLocal";threadLocal.set(str);System.out.println("main thread set value:" + str);new Thread() {@Overridepublic void run() {String str = threadLocal.get();System.out.println("sub thread get value:" + str);}}.start();str = threadLocal.get();System.out.println("main thread get value:" + str);}

输出结果:

main thread set value:Test ThreadLocal
main thread get value:Test ThreadLocal
sub thread get value:null

一个线程set的值,其他线程取不到,只有相同线程才能取到。多个线程同时用一个ThreadLocal对象,其数据是还是属于各自线程。

多少个对象就能存多少个数据

由于是泛型,所以多个ThreadLocal不但可以存多个同类型的对象,甚至可以存多个不同类型的 对象。

static void testThreadLoacals() {final ThreadLocal<String> threadLocal = new ThreadLocal<>();final ThreadLocal<A> threadLocal1 = new ThreadLocal<>();String str = "main Thread";threadLocal.set(str);System.out.println("threadLocal main thread set str value:" + str);A a = new A();threadLocal1.set(a);System.out.println("threadLocal1 main thread set A class value:" + a);new Thread() {@Overridepublic void run() {String str = threadLocal.get();System.out.println("sub thread get value:" + str);str = "sub thread";threadLocal.set(str);System.out.println("sub thread set value:" + str);System.out.println("sub thread set value:" + threadLocal.get());}}.start();str = threadLocal.get();System.out.println("main thread 1 get value:" + str);System.out.println("main thread 1 get A class value:" + threadLocal1.get());try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}System.out.println("main thread 2 get value:" + threadLocal.get());}

threadLocal set 一个String
threadLocal1 set的是A类的对象

输出结果:

threadLocal main thread set str value:main Thread
threadLocal1 main thread set A class value:com.eagle.app.MainJava$A@12a3a380
main thread 1 get value:main Thread
main thread 1 get A class value:com.eagle.app.MainJava$A@12a3a380
sub thread get value:null
sub thread set value:sub thread
sub thread set value:sub thread
main thread 2 get value:main Thread

多个线程同时用多个ThreadLocal对象,其数据是还是属于各自线程。


  1. Java中ThreadLocal的实际用途是啥 ↩︎

  2. ingxin ThreadLocal ↩︎

ThreadLocal初识相关推荐

  1. FastThreadLocal吞吐量居然是ThreadLocal的3倍

    目前关于FastThreadLocal的很多文章都有点老有点过时了(本文将澄清几个误区),很多文章关于FastThreadLocal介绍的也不全,希望本篇文章可以带你彻底理解FastThreadLoc ...

  2. day3----编码-集合-深浅copy-文件操作-函数初识

    day3----编码-集合-深浅copy-文件操作-函数初识 本文档主要内容: 一 编码 二 集合 三 深浅copy 四 文件操作 五 函数初识 首先,我们来看看两个字符串的比较 打开cmd,进入do ...

  3. ⑥python模块初识、pyc和PyCodeObject

    一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...

  4. 初识java类的接口实现

    初识java类的接口实现 如果两个类之间不存在继承关系,且两个类都想实现同一个接口,两个类都必须实现接口中全部方法,否则报语法错误 如果两个类之间存在继承关系也想实现同一个接口,父类如果实现了某个接口 ...

  5. 正确理解ThreadLocal

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt107 首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的, ...

  6. 什么是ThreadLocal

    顾名思义它是local variable(线程局部变量).它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突.从线 ...

  7. 为什么jdk源码推荐ThreadLocal使用static

    ThreadLocal是线程私有变量,本身是解决多线程环境线程安全,可以说单线程实际上没必要使用. 既然多线程环境本身不使用static,那么又怎么会线程不安全.所以这个问题本身并不是问题,只是有人没 ...

  8. Spring源码分析【6】-ThreadLocal的使用和源码分析

    Spring代码使用到了ThreadLocal java.lang.ThreadLocal.set getMap java.lang.Thread.threadLocals定义 回到set 如果map ...

  9. vba 编辑combobox内容_初识Visual Basic编辑器并建立一段简单的代码

    大家好,从今日开始我正式推出"VBA之EXCEL应用"教程,这个教程是面向初学人员的教程,教程一共三册,十七个章节,从简单的录制宏实现一直讲到窗体的搭建,都是我们在利用EXCEL工 ...

最新文章

  1. 统计学习笔记(4)——朴素贝叶斯法
  2. sql getdate() 时间格式设置
  3. ABAP在ALV工具栏显示一个计时器
  4. VC++下的OpenGL编程
  5. Hadoop Hive替换自带的derby数据库为MySQL具体步骤
  6. pmp每日三题(2022年2月25日)
  7. Leetcode题库 19.删除链表的倒数第N个结点(双指针法 C实现)
  8. 在res/values下创建attrs.xml
  9. 米斯特白帽培训讲义 工具篇 Nmap
  10. 硬盘属于计算机主机吗,电脑主机换硬盘后还是不是原来的主机?
  11. 评分卡模型开发(九)--上线监测
  12. {ubuntu}乱七八糟重命名为1 2 3.....png
  13. jmteter 参数提取器-使用正则表达式来提取数据
  14. 计算机固态加机械硬盘,固态硬盘和机械硬盘怎么混合使用
  15. C盘太小,调整磁盘分区大小
  16. 记录一下wandb的用法
  17. MWC 2018前瞻:三星华为诺基亚们会展示这些黑科技!
  18. Easyrecovery教你Excel表格数据恢复
  19. win10搭建网络代理,供Linux使用
  20. 三菱4轴控制伺服案例,三菱PLC FX3U加三菱1PG定位模 块控制4个松下伺服,有完整的注释,结构清晰明了。伺服控制程序JOG HOME 定位 全部写成了功能块FB .你可以直接拿过去用

热门文章

  1. MySQL 精选 60 道面试题(含答案)
  2. 《大厂内部资料》Redis 性能优化的 13 条军规!全网首发
  3. linux——两个客户端之间实现聊天(TCP、单线程)
  4. 六、华为鸿蒙HarmonyOS应用开发之Java开发模式下的不同Page 间实现页面跳转
  5. C++ SVM Opencv3.4实现人脸检测
  6. php7 有参数类型,PHP7中的可空返回类型
  7. ztree 指定节点清空_节点操作
  8. 台式计算机更新不了,台式机更新造成电脑关不了机怎么办
  9. c语言sort函数排序二维数组,js 二维数组排序sort()函数
  10. linux vps 运行exe文件夹,在centos环境下运行.exe文件