ThreadLocal初识

目录

  • 背景
  • 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 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gensee SDK UserInfo类函数详细说明

目录基本信息rolestatusclientType其他UserInfo是一个公共的类&#xff0c;用于RtSDK和PlayerSDK。由于role和status是复合1量&#xff0c;列出相关的判断方式&#xff0c;true为注释说明&#xff0c;false反之。 如 isHost() true 老师/false 不是老师。 基本信息 getUserId…

python中shutil模块_Python中shutil模块的学习笔记教程

介绍shutil 名字来源于 shell utilities&#xff0c;有学习或了解过Linux的人应该都对 shell 不陌生&#xff0c;可以借此来记忆模块的名称。该模块拥有许多文件(夹)操作的功能&#xff0c;包括复制、移动、重命名、删除等等一、chutil.copy(source, destination)shutil.copy()…

HTML转义字符大全<转>

为什么要用转义字符串&#xff1f; HTML中<&#xff0c;>&#xff0c;&等有特殊含义&#xff08;<&#xff0c;>&#xff0c;用于链接签&#xff0c;&用于转义&#xff09;&#xff0c;不能直接使用。这些符号是不显示在我们最终看到的网页里的&#xff0c…

python测网速_tespeed-测试网速的Python工具

1.安装(环境CentOS7)#pip install lxml#wget wget http://sourceforge.net/projects/socksipy/files/socksipy/SocksiPy%201.00/SocksiPy.zip#git clone https://github.com/Janhouse/tespeed.git#mv SocksiPy.zip tespeed/SocksiPy/#cd tespeed/SocksiPy/#unzip SocksiPy.zip#…

Gensee SDK RoleType详解

目录RoleType使用场景&#xff1a;方法与使用说明源码RoleType 接着之前的 UserInfo,对RoleType做进一步说明. 此类是SDK的公共类&#xff0c;可以在任一SDK使用方进行调用&#xff0c;之前有提到role是一个“复合”的值1&#xff0c;所以不能简单的用“” 来判断&#xff0c;…

vc 通过句柄修改窗口大小_漫画:对象是如何被找到的?句柄 OR 直接指针?

小贴士&#xff1a;想要使用并定位 Java 对象&#xff0c;就要用到 Java 虚拟机栈&#xff08;Java Virtual Machine Stack&#xff09;&#xff0c;它描述的是 Java 方法执行的线程内存模型&#xff1a;每个方法被执行的时候&#xff0c;Java 虚拟机都会同步创建一个栈帧&…

数据结构快速掌握和温习-面试神器

由于原文有部分文字没有显示&#xff0c;本文有所修改。主要包括文字和缩进。 目录 Q1&#xff1a;数据结构和算法的知识点整理&#xff1a; Q2&#xff1a;链表&#xff0c;队列和栈的区别 Q3&#xff1a;简述快速排序过程 Q4&#xff1a;快速排序算法的原理 Q5&#xff1a;简…

python阴阳师_如何用Python找到阴阳师妖怪屋的最佳探索队伍!强不强?

程序由来最初想要写这个小程序是因为&#xff0c;9月份那段时间我在玩妖怪屋。因为刚开始抽卡&#xff0c;要啥啥没有&#xff0c;所以探索队伍也只是放了几个自己记得有关联的式神。在网上有找到完整版的羁绊&#xff0c;但是怎么根据羁绊找到最佳的式神组合就成问题了。当时我…

Android iOS防录屏截屏

目录Android防录屏和截屏关于WindowManager.LayoutParams.FLAG_SECURE关于Display.FLAG_SECUREiOS防录屏和截屏监听截屏录屏监听需求与安全总是对立的&#xff0c;有新的需求&#xff0c;就有新的接口开放&#xff0c;但随之而来的就是利用新接口或者新接口的使用者&#xff08…

work节点使用外部包_AFLSmart工具简单分析及使用介绍

AFLSmart 是一个在 AFL 基础上&#xff0c;结合了 Peach 的结构化输入组件的灰盒 smart fuzz 工具。AFLSmart 链接&#xff1a;https://github.com/aflsmart/aflsmart参考资料&#xff1a;《Smart Greybox Fuzzing》什么是 AFLSmart灰盒 smart fuzz灰盒测试是基于程序运行时刻的…

Android adb 启动APP

目录启动命令一 常规命令 包名/activity二 常规命令 包名命令关闭App获取包名和activity的路径代码获取1 命令获取( 需要app运行在前台&#xff0c;停留在启动界面)2命令获取(先执行命令&#xff0c;再点击app启动)启动命令 一 常规命令 包名/activity adb shell am start…

python语言使用什么语句实现上下文管理协议_Python 上下文管理器

上下文管理器在使用Python编程中&#xff0c;可以会经常碰到这种情况&#xff1a;有一个特殊的语句块&#xff0c;在执行这个语句块之前需要先执行一些准备动作&#xff1b;当语句块执行完成后&#xff0c;需要继续执行一些收尾动作。例如&#xff1a;当需要操作文件或数据库的…

Android日志[基础篇]Android Log日志输出

Android日志[基础篇]二 Android Studio修改LogCat日志的颜色 android.util.Log输出日志的常用方法如下&#xff1a; Log.v(String tag, String msg)Log.d(String tag, String msg)Log.i(String tag, String msg)Log.w(String tag, String msg)Log.e(String tag, String msg) …

python函数应用_python 函数应用

#函数的参数就是个变量#定义函数的时候&#xff0c;使用关键字参数&#xff0c;可以指定默认值def hello(namereboot,age1):return hello %s,your age is %s %(name,age)print hello(reboot,3)print hello(3,reboot)#print hello(age3,namereboot)print hello(reboot)def f(n):…

Android日志[基础篇]二 Android Studio修改LogCat日志的颜色

上一篇提到Android日志的5个级别的日志输出&#xff0c;在logcat里面设置自己喜欢或习惯的颜色&#xff0c;本文不只讲Android Sudio修改logcat的日志颜色。 代码和效果 代码 private void logColor(){Log.v(TAG,"logColor verbose");Log.d(TAG,"logColor de…

readfile函数使用方法_1分钟学会LOOKUP函数,有网友说使用这个方法,初学者秒变大神...

Hi&#xff0c;大家好&#xff0c;本专栏将会从零开始和大家用图文的方式&#xff0c;30天让你从不会到熟练使用函数&#xff0c;0基础开始学习Excel函数&#xff0c;让你喜欢上它&#xff01;有兴趣的小伙伴可以持续关注我&#xff0c;或者在专栏进行查看学习&#xff0c;愿与…

Android JNI Attempt to remove non-JNI local reference, dumping thread

Attempt to remove non-JNI local reference, dumping thread 解决办法&#xff1a; 去除Jni代码 env->DeleteLocalRef(javaObject);注意&#xff1a;是java层传递给jni层的对象不需用了DeleteLocalRef来进行对象删除&#xff0c;jni层创建的对象仍然需要保留代码。 这个…

背景图层和普通图层的区别_图层样式(一)—高级混合选项

一、图层顺序为了便于说明&#xff0c;首先建立例子&#xff0c;新建图层&#xff0c;用画笔随便画个圈&#xff0c;新建蒙版随便画一笔&#xff0c;然后把所有图层样式加给它。可以看到样式从上到下的顺序&#xff0c;这也是它们混合的图层顺序。图层顺序我的效果&#xff0c;…

Android9.0 http网络请求失败问题的处理

目录处理方法(任意一种)&#xff1a;APP改用https请求targetSdkVersion 降到27以下配置network-security-config&#xff08;推荐&#xff09;原因出错案例处理方法(任意一种)&#xff1a; APP改用https请求 这种方式是最佳方法&#xff0c;需要前后端协调&#xff0c;后端得…

代码里无图片地址_项目实战:爬高清图片

↑ 关注 星标 &#xff0c;后台回复【大礼包】送你2TPython自学资料好消息&#xff1a;Python学习交流群&#xff0c;已经建立&#xff0c;猛戳加入之前我发过一些爬虫的文章&#xff0c;不过一直没发过爬取图片的&#xff0c;今天就给大家分享一篇吧&#xff01;/1 前言/上篇…