不同角度看Handler——另类三问
之前有一章节介绍了Handler的常见面试题,今天就来说说另类的,可能你没关注的其他问题,一起看看吧。
系统为什么提供Handler
- 这点大家应该都知道一些,就是为了切换线程,主要就是为了解决在子线程无法访问UI的问题。
那么为什么系统不允许在子线程中访问UI呢?
- 因为
Android的UI控件不是线程安全的,所以采用单线程模型来处理UI操作,通过Handler切换UI访问的线程即可。
那么为什么不给UI控件加锁呢?
- 因为加锁会让
UI访问的逻辑变得复杂,而且会降低UI访问的效率,阻塞线程执行。
Handler是怎么获取到当前线程的Looper的
- 大家应该都知道
Looper是绑定到线程上的,他的作用域就是线程,而且不同线程具有不同的Looper,也就是要从不同的线程取出线程中的Looper对象,这里用到的就是ThreadLocal。
假设我们不知道有这个类,如果要完成这样一个需求,从不同的线程获取线程中的Looper,是不是可以采用一个全局对象,比如hashmap,用来存储线程和对应的Looper?所以需要一个管理Looper的类,但是,线程中并不止这一个要存储和获取的数据,还有可能有其他的需求,也是跟线程所绑定的。所以,我们的系统就设计出了ThreadLocal这种工具类。
ThreadLocal的工作流程是这样的:我们从不同的线程可以访问同一个ThreadLocal的get方法,然后ThreadLocal会从各自的线程中取出一个数组,然后再数组中通过ThreadLocal的索引找出对应的value值。具体逻辑呢,我们还是看看代码,分别是ThreadLocal的get方法和set方法:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
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();
}
首先看看set方法,获取到当前线程,然后取出线程中的threadLocals变量,是一个ThreadLocalMap类,然后将当前的ThreadLocal作为key,要设置的值作为value存到这个map中。
get方法就同理了,还是获取到当前线程,然后取出线程中的ThreadLocalMap实例,然后从中取到当前ThreadLocal对应的值。
其实可以看到,操作的对象都是线程中的ThreadLocalMap实例,也就是读写操作都只限制在线程内部,这也就是ThreadLocal故意设计的精妙之处了,他可以在不同的线程进行读写数据而且线程之间互不干扰。
画个图方便理解记忆:

当MessageQueue 没有消息的时候,在干什么,会占用CPU资源吗。
MessageQueue没有消息时,便阻塞在 loop 的queue.next()方法这里。具体就是会调用到nativePollOnce方法里,最终调用到epoll_wait()进行阻塞等待。
这时,主线程会进行休眠状态,也就不会消耗CPU资源。当下个消息到达的时候,就会通过pipe管道写入数据然后唤醒主线程进行工作。
这里涉及到阻塞和唤醒的机制叫做 epoll 机制。
先说说文件描述符和I/O多路复用:
在Linux操作系统中,可以将一切都看作是文件,而文件描述符简称fd,当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符,可以理解为一个索引值。
I/O多路复用是一种机制,让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作
所以I/O多路复用其实就是一种监听读写的通知机制,而Linux提供的三种 IO 复用方式分别是:select、poll 和 epoll 。而这其中epoll是性能最好的多路I/O就绪通知方法。
所以,这里用到的epoll其实就是一种I/O多路复用方式,用来监控多个文件描述符的I/O事件。通过epoll_wait方法等待I/O事件,如果当前没有可用的事件则阻塞调用线程。
拜拜
今天就说这么多了,感兴趣的朋友也可以继续深究下去,比如epoll为什么是性能最好的I/O多路复用方法?Handler在App启动流程中涉及到了哪些功能?等等。有机会再和大家聊聊~
有一起学习的小伙伴可以关注下️我的公众号——码上积木,每天剖析一个知识点,我们一起积累知识。
不同角度看Handler——另类三问的更多相关文章
- Android IOS WebRTC 音视频开发总结(四八)-- 从商业和技术的角度看视频行业的机会
本文主要从不同角度介绍视频行业的机会,文章来自博客园RTC.Blacker,支持原创,转载必须说明出处,欢迎关注个人微信公众号blacker ----------------------------- ...
- 从线程模型的角度看Netty的高性能
转载:Netty(二) 从线程模型的角度看 Netty 为什么是高性能的? 传统 IO 在 Netty 以及 NIO 出现之前,我们写 IO 应用其实用的都是用 java.io.* 下所提供的包. 比 ...
- 深度挖坑:从数据角度看人脸识别中Feature Normalization,Weight Normalization以及Triplet的作用
深度挖坑:从数据角度看人脸识别中Feature Normalization,Weight Normalization以及Triplet的作用 周翼南 北京大学 工学硕士 373 人赞同了该文章 基于深 ...
- Swift 枚举-从汇编角度看枚举内存结构
一.基本使用 先看枚举的几种使用(暂不要问,看看是否都能看懂,待会会逐一讲解) 1.操作一 简单使用 //第一种方式 enum Direction { case east case west case ...
- [置顶] 从引爆点的角度看360随身wifi的发展
从引爆点的角度看360随身wifi的发展 不到一个月的时间,随身wifi预定量就数百万.它的引爆点在哪里,为什么相同的产品这么多它却能火起来,通过对随身wifi的了解和我知识层面分析,主要是因为随身w ...
- 从源码的角度看Service是如何启动的
欢迎访问我的个人博客 ,原文链接:http://wensibo.top/2017/07/16/service/ ,未经允许不得转载! 七月中旬了,大家的实习有着落了吗?秋招又准备的怎么样了呢?我依旧在 ...
- RESTful三问
我觉得学习一个技术,其实就是要弄明白三件事情:是什么(what),为什么(why),怎么用(how).正是所谓的三W方法. 所以打算总结一个"三问"系列.为了自己学习,也分享给别人 ...
- Android学习笔记——从源码看Handler的处理机制
可能是出于性能的考虑,Android的UI操作是非线程安全的. 也就是说,如果你在一个新开的线程中直接操作UI是会引发异常的. 但是,Android又规定,不要去阻塞UI线程!否则,轻者引起程序卡顿, ...
- 从JDK源码角度看Short
概况 Java的Short类主要的作用就是对基本类型short进行封装,提供了一些处理short类型的方法,比如short到String类型的转换方法或String类型到short类型的转换方法,当然 ...
随机推荐
- Spring mvc文件上传实现
Spring mvc文件上传实现 jsp页面客户端表单编写 三个要素: 1.表单项type="file" 2.表单的提交方式:post 3.表单的enctype属性是多部分表单形式 ...
- 转 mysql show processlist 查看当前连接
show processlist和show full processlist processlist命令的输出结果显示了有哪些线程在运行,不仅可以查看当前所有的连接数,还可以查看当前的连接状态帮助识别 ...
- 如何使用 Gin 和 Gorm 搭建一个简单的 API 服务 (一)
介绍 Go 语言最近十分火热,但对于新手来说,想立马上手全新的语法和各种各样的框架还是有点难度的.即使是基础学习也很有挺有挑战性. 在这篇文章中,我想用最少的代码写出一个可用的 API 服务. ...
- centos下安装mongodb 通过shell脚本
#! /bin/bash yum -y update echo -e "开始安装mongodb\n" download_url=https://fastdl.mongodb.o ...
- postgresql 导出数据库与数据表
单表导出 pg_dump --host 127.0.0.1 --port 5432 --username "postgres" --role "postgres" ...
- vue-awesome-swiper ---移动端h5 swiper 和 tab 栏选项联动效果实现
很久之前做小程序时有个类似每日优鲜里储值卡充值界面里的 卡轮播和价格tab栏联动效果,当时觉得新鲜做出来之后也没当回事.直到今天又遇到了一个类似的功能,所以想着总结经验. 实现效果如下图: 图解:点击 ...
- Java进阶专题(十五) 从电商系统角度研究多线程(下)
前言 本章节继上章节继续梳理:线程相关的基础理论和工具.多线程程序下的性能调优和电商场景下多线程的使用. 多线程J·U·C ThreadLocal 概念 ThreadLocal类并不是用来解决 ...
- 立即执行函数 - Js函数笔记
立即执行函数 定义:此类函数没有声明,在执行一次后即释放,适合做初始化. 针对初始化功能的函数,同时遵循一句话,只有表达式才能被执行符号执行 1.(function() {...}()); - W3C ...
- 作用域 - Js深入理解笔记
执行期上下文 当函数执行时,会创建一个称为执行上下文的内部对象 一个执行期上下文定义了一个函数所执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,多次调用一个函数会导致创建多个执行上下文,当 ...
- Java中的微信支付(1):API V3版本签名详解
1. 前言 最近在折腾微信支付,证书还是比较烦人的,所以有必要分享一些经验,减少你在开发微信支付时的踩坑.目前微信支付的API已经发展到V3版本,采用了流行的Restful风格. 今天来分享微信支付的 ...
