概述

我们在谈Handler机制的时候,其实也就是谈Handler、Message、Looper、MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解)。

  • Message:Handler发送、接收和处理的消息对象
  • Looper:每个线程只能拥有一个Looper.它的looper()方法负责循环读取MessageQueue中的消息并将读取到的消息交给发送该消息的handler进行处理。
  • MessageQueue:消息队列,它采用先进先出的方式来管理Message。程序在创建Looper对象时,会在它的构造器中创建MessageQueue。

Handler类简析

Handler类的主要作用有两个:在新启动的线程中发送消息;在主线程中获取和处理消息。
而要完整的理解Handler机制,对于Looper的底层存储和轮询机制是必须了解的,看过了其实就很简单,今天就专门讲这个。

ThreadLocal详解

为了方便大家理解,我们直接看源码:

public class ThreadLocal<T> {.....
}

这里可以看出threadlocal是一个范型类,这标志着threadlocal可以存储所有数据,作为存储数据来说,我们首先想到的是会对外提供set(),get(),remove(),等方法。
set()方法:

 /*** 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);}

从源码可以看出,首先获取当前线程,然后调用values方法,我们来看下values方法:

/*** Gets Values instance for this thread and variable type.*/Values values(Thread current) {return current.localValues;}

该方法是返回当前线程的一个存储实类,那ThreadLocal又是什么呢?上面说过 ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据。
我们来看几个ThreadLocal方法,先回到set方法,得到values的实类以后会来一个判断,为null调用initializeValues(currentThread)

 Values initializeValues(Thread current) {return current.localValues = new Values();}

接下来调用value的put方法,我们想到的应该是往里面插值,也就是我们说的put()。

 void put(ThreadLocal<?> key, Object value) {cleanUp();// Keep track of first tombstone. That's where we want to go back// and add an entry if necessary.int firstTombstone = -1;for (int index = key.hash & mask;; index = next(index)) {Object k = table[index];if (k == key.reference) {// Replace existing entry.table[index + 1] = value;return;}if (k == null) {if (firstTombstone == -1) {// Fill in null slot.table[index] = key.reference;table[index + 1] = value;size++;return;}// Go back and replace first tombstone.table[firstTombstone] = key.reference;table[firstTombstone + 1] = value;tombstones--;size++;return;}// Remember first tombstone.if (firstTombstone == -1 && k == TOMBSTONE) {firstTombstone = index;}}}

从源码可以看出,把values的值传入到一个table数组的key.reference的下一个下标中,至此,我们了解了Threadlocal的存值过程,首先会获取当前线程,根据当前线程获取Values存储类,该存储类在该线程是单例的,在调用values存储类中的put方法,最终将存储的内容存储到Values内部类的table数组下标为key.reference中 。
接下来我们来看一下取值的方法:

  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);}

ThreadLocal的get方法的逻辑也比较清晰,它同样是取出当前线程的localValues对象,如果这个对象为null那么就返回初始值,初始值由ThreadLocal的initialValue方法来描述。

  protected T initialValue() {return null;}

如果localValues对象不为null,那就取出它的table数组并找出ThreadLocal的reference对象在table数组中的位置,然后table数组中的下一个位置所存储的数据就是ThreadLocal的值。
接着我们再来看一下remove的方法实现:

 void remove(ThreadLocal<?> key) {cleanUp();for (int index = key.hash & mask;; index = next(index)) {Object reference = table[index];if (reference == key.reference) {// Success!table[index] = TOMBSTONE;table[index + 1] = null;tombstones++;size--;return;}if (reference == null) {// No entry found.return;}}}

到此我们就完全明白了ThreadLocal的存取原理了:通过ThreadLocal的set和get方法可以看出,它们所操作的对象都是当前线程的localValues对象的table数组,因此在不同线程中访问同一个ThreadLocal的set和get方法,它们对ThreadLocal所做的读写操作仅限于各自线程的内部,这就是为什么ThreadLocal可以在多个线程中互不干扰地存储和修改数据。

android Handler机制之ThreadLocal详解相关推荐

  1. android message 代码,Android Handler移除Message详解及实例代码

    Android Handler移除Message详解 问题: 1.removeMessage(what)函数是否只能移除对应what值的Message? 2.对于Delayed发送的Message,能 ...

  2. Android签名机制-签名过程详解

    目录 一.前言 二.准备知识 1.数据摘要 2.签名文件和证书 3.jarsign和signapk工具 4.keystore文件和pk8,x509.pem文件的区别 5.手动的签名Apk包 三.分析A ...

  3. Android 广播机制以及用法详解 (转)

    转:http://blog.sina.com.cn/s/blog_5da93c8f010178zl.html 参考:http://blog.sina.com.cn/s/blog_80723de8010 ...

  4. Android异步处理三:Handler+Looper+MessageQueue深入详解

    本博文地址:http://blog.csdn.net/mylzc/article/details/6771331 转载请注明出处 Android异步处理系列文章索引 Android异步处理一:使用Th ...

  5. Android Loader 异步加载详解二:探寻Loader内部机制

    Android Loader 异步加载详解二:探寻Loader内部机制 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/7025991 ...

  6. Android Telephony分析(三) ---- RILJ详解

    前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程.  这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\And ...

  7. Android Loader 异步加载详解一:基础概念

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/70241844 本文出自[赵彦军的博客] Android Loader 异步加载详解 ...

  8. Android之AsyncTask异步任务详解总结

    Android 多线程----AsyncTask异步任务详解 [正文] 本文将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信. 一.Android当中的多 ...

  9. 【胖虎的逆向之路】02——Android整体加壳原理详解实现

    [胖虎的逆向之路](02)--Android整体加壳原理详解&实现 Android Apk的加壳原理流程及详解 文章目录 [胖虎的逆向之路](02)--Android整体加壳原理详解& ...

最新文章

  1. 集体智慧及其常用算法
  2. MySQL数据库:完整性约束
  3. 刷固件Layer1到手机FLASH(硬刷)
  4. 2016年第七届蓝桥杯 - 国赛 - Java大学C组 - A. 平方末尾
  5. 尝鲜!.NET5实操之docker+k8s,这10个坑,你不得不知!
  6. ASP.NET MVC多语言 仿微软网站效果(转)
  7. mysql 引擎 类型_MySQL(一)之存储引擎类型
  8. denied git permission_Git使用之Permission Denied问题解决[2153-Noblog]
  9. Java常用的工具类库介绍
  10. 【Django 2021年最新版教程5】前端传递数据到后端处理 GET 方法
  11. 给tomcat指定JDK
  12. 微信小程序下载文件,后端PHP处理流程
  13. Hex Editor Crack版,十六进制编辑器使用方案
  14. 常用图像处理库都有哪些?
  15. VOCALOID笔记
  16. 浏览器缓存机制:强缓存和协商缓存
  17. 新胖子公式(java)
  18. LibJpeg的安装与修复颜色错误图像错位保姆级教程
  19. js简单实现根据身份证号码识别性别年龄生日
  20. 苏世民,我的经验和教训(一)

热门文章

  1. cplex学术版安装
  2. C#调用API向外部程序发送数据(转载)
  3. C++类构造函数中的成员初始化
  4. css border制作小三角形状及应用(兼容IE6)
  5. 如何使用 System.IO 和 Visual C# 读取文本文件
  6. 数据增强_开源算法FMix:用于深度学习中增强混合样本数据增强
  7. oa 中会议推送 实现_诗尼曼:大OA+费控赋能千店一体,打造家居数字化标杆
  8. 改变路径但是不让它跳转_Vue实战047:Breadcrumb面包屑实现导航路径
  9. 标记三维点_细胞器相互作用过程的高速三维全景成像
  10. C语言定义code报错,C语言报错整理大全