主要功能:

针对一个对象,每个线程需要存储不同的值的时候,使用ThreadLocal会非常的方便。

图解:

针对一个全局变量local,线程1-4都持有local的引用。当线程分别对local进行修改后,其实修改作用域仅限当前线程可用。

public class ThreadLocalTest {//对thread1-4均可见的mThreadLocal,相当于上图中的String local变量private ThreadLocal<String> mThreadLocal = new ThreadLocal<String>() ;//设定一个锁,好对线程进行同步private final Object setLock = new Object() ;Thread t1 = new Thread(){public void run(){synchronized (setLock) {mThreadLocal.set("I'm t1");try {setLock.wait();} catch (InterruptedException e) {e.printStackTrace();}}Log.d("gggl" , mThreadLocal.get()) ;}} ;Thread t2 = new Thread(){public void run(){synchronized (setLock) {mThreadLocal.set("I'm t2");try {setLock.wait();} catch (InterruptedException e) {e.printStackTrace();}}Log.d("gggl" , mThreadLocal.get()) ;}} ;Thread t3 = new Thread(){public void run(){synchronized (setLock) {mThreadLocal.set("I'm t3");try {setLock.wait();} catch (InterruptedException e) {e.printStackTrace();}}Log.d("gggl" , mThreadLocal.get()) ;}} ;Thread t4 = new Thread(){public void run(){synchronized (setLock) {mThreadLocal.set("I'm t4");try {setLock.wait();} catch (InterruptedException e) {e.printStackTrace();}}Log.d("gggl" , "t4 " + this.getState()) ;Log.d("gggl" , mThreadLocal.get()) ;}} ;public void test(){mThreadLocal.set("I'm main");t1.start() ;t2.start() ;t3.start();t4.start();try {Thread.sleep(500) ;synchronized (setLock) {setLock.notifyAll();}} catch (Exception e) {e.printStackTrace();}Log.d("gggl" , mThreadLocal.get()) ;}
}
/**打印结果2022-09-15 14:46:09.873 12915-15252/com.example.interview D/gggl: I'm t12022-09-15 14:46:09.873 12915-15253/com.example.interview D/gggl: I'm t22022-09-15 14:46:09.873 12915-15254/com.example.interview D/gggl: I'm t32022-09-15 14:46:09.873 12915-12915/com.example.interview D/gggl: I'm main2022-09-15 14:46:09.873 12915-15255/com.example.interview D/gggl: t4 RUNNABLE2022-09-15 14:46:09.873 12915-15255/com.example.interview D/gggl: I'm t4
* */

分析:

首先介绍几个相关类:Thread、ThreadLocal、ThreadLocalMap,这三个类的大致关于如下。

ThreadLocalMap是最后存储数据的类,为ThreadLocal的静态内部类,内部包含一个Entry[] table的数组。Entry的key是ThreadLocal,value为我们调用set方法的时候设置的值。

Thread持有ThreadLocal的引用,这表明每创建一个线程都会对应的创建出一个ThreadLocalMap(注:lazyload,因为并不是每个线程都有使用ThreadLocal的功能)。

ThreadLocal内部有两个常用方法set,get用于数据的存储。当调用set、get方法时第一句都是Thread.currentThread()首先获取当前线程的引用。所以后续的操作确保了作用域只在当前线程。当调用set方法时,最终调用的其实时 map.set(this, value),意为着向当前线程的成员变量MAP中存入了一个键值对,由于map为每个线程的成员变量,所以我们调用set存入的值得作用域也仅限当前线程。

public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}
public T get() {Thread t = Thread.currentThread();ThreadLocalMap 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();
}
ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}

Android Looper的线程唯一性

做过Android开发的同学应该都知道在android中只要线程调用了Looper.prepa()后就会在对应的线程创建一个looper,并且每个线程都只能有一个looper对象,每个线程的looper对象都不相同,正是使用了ThreadLocal达到的特性。

    private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}

sThreadLocal是ThreadLocal的静态变量,说明所有的Thread共有sThreadLocal变量。在内存中的存放形式就相当于有一个Map存放了进程内的所有Looper。这个Map的key就是每个线程的ThreadLocal

2022面试Android之ThreadLocal相关推荐

  1. 2022面试Android之单例模式

    单例模式大致可以分为两类,懒汉模式和饿汉模式,但是不必在意是懒还是饿,还是要明白他们的原理和区别.(什么是懒汉,就是类加载了之后,并没有实例化单例,而是延后到第一次使用的时候:什么事恶汉,就是类加载了 ...

  2. sqlserver2008未将对象引用设置到对象的实例_面试官:ThreadLocal 的内存泄漏是弱引用导致的,你确定?...

    面试官:ThreadLocal 了解吗? Python 小星:线程局部变量,多线程下能保证各个线程的变量相对独立于其他线程的变量. 面试官:那你说下它是如何保证线程隔离的? Python 小星:每个线 ...

  3. 腾讯面试Android高级岗。居然被一个多线程基础面倒了?

    前言 一个在深圳从事开发五年的老友一个月前从原公司辞职后,昨天去腾讯总部面试Android高级岗,一面的时候,自我介绍后,陆陆续续问了很多问题,有着五年的从业经验很多项目开发的技术问题都回答的很通顺, ...

  4. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第六章:数据存储

    第 6 章 数据存储 本章介绍Android 4种存储方式的用法,包括共享参数SharedPreferences.数据库SQLite.存储卡文 件.App的全局内存,另外介绍Android重要组件-应 ...

  5. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第五章:中级控件

    第 5 章 中级控件 本章介绍App开发常见的几类中级控件的用法,主要包括:如何定制几种简单的图形.如何使用几种选择按钮.如何高效地输入文本.如何利用对话框获取交互信息等,然后结合本章所学的知识,演示 ...

  6. 2022 最新 Android studio添加阿里云Aliyun Maven仓库

    2022 最新 Android studio添加阿里云Aliyun Maven仓库 网上看了很多的文章,都是老文章,要不就是AS是老版本,我是个新手,也不懂AS老了有啥好的,所以下载AS的时候,默认就 ...

  7. 2022年Android中高级面试框架

    目录 Java 泛型 集合 ArrayList LinkedList HashMap LinkedHashMap ConcurrentHashMap 多线程并发 volatile 线程 反射 JVM ...

  8. 2022中级Android开发面试解答,当上项目经理才知道

    缘起 随着互联网企业的不断发展,产品项目中的模块越来越多,用户体验要求也越来越高,想实现小步快跑.快速迭代的目的越来越难,还有65535,应用之间的互相调用等等问题,插件化技术应用而生.如果没有插件化 ...

  9. android面试自我介绍范文,2022年Android技术下半场在哪

    开头 中国互联网发展的这些年,如今90后程序员是中国程序员的主力军,互联网的热潮也让一批批00后蠢蠢欲动,尝试涌入互联网圈. 当程序员容易,当一个优秀的程序员需要不断学习,从初级程序员到高级程序员,从 ...

最新文章

  1. 第六篇:并发-粒度锁
  2. 示波器上mode选择开关上的norm和auto是什么意思?
  3. js跨域请求方式 ---- JSONP原理解析
  4. delphi 如何判断编码格式,解决乱码问题
  5. Index of Unix
  6. LDAP第三天 MySQL+LDAP 安装
  7. Unity引擎及编辑器C#源代码发布
  8. C语言三目运算符 - C语言零基础入门教程
  9. 【课后习题】数值计算方法期末复习
  10. javascript挑战编程技能-第九题:数据结构
  11. python在材料模拟中的应用_材料模拟在计算机中使用的软件
  12. HDOJ 汉诺塔系列(递推分析)
  13. 算法笔记 --- 布隆过滤器
  14. redmi路由器是linux,拯救小米路由器硬盘数据的方法及软件下载
  15. 新版本vivado打开老工程ip核被锁住的解决方法
  16. 珠海到各大机场的线路
  17. 微信从原版到现在所有界面图片_微信这4张登录界面图,你见过几张?微信老用户都不一定能认全!...
  18. css实现旋转的小流星动画
  19. 什么是信令?什么是信令网?(转)
  20. QT中使用C++ socket通信,socket通信原理三次握手和四次握手详解、客户端与服务端实例详解

热门文章

  1. word怎么根据点画曲线_用word怎么画曲线图 word里如何绘制曲线图
  2. python3 实现火车票查询 代码+知识点
  3. 页面找不到了无法解析服务器,win10下搜狗浏览器无法解析服务器的dns地址如何解决...
  4. jmeter与lr区别
  5. Win10鼠标点一下文件夹或文件没有选中的那个蓝色,但还是能正常用,比如双击跟右键,点一下也有详细信息
  6. aws上传找不到endpoint url或者The Aws Access Key Id you provided does not exist in our recordss
  7. SAP MM 采购申请列表选择条件说明
  8. Swing设置窗体背景图片
  9. win7 解决飞秋无法接收文件(准备接收)问题
  10. C#框架设计之浅谈SOA与钝化模式