Skip to content

Commit d80b20a

Browse files
committed
multithreading
1 parent 470f9d1 commit d80b20a

8 files changed

Lines changed: 54 additions & 30 deletions

‎README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ Android 章节的内容包括:四大组件、权限系统、官方框架、自
137137
* [Gradle 常用配置总结](https://github.com/leavesC/GradleSamples)
138138
* [RxJava2 入门详细笔记](notes/RxJava2入门详细笔记.md)
139139
* [Dagger2 入门笔记](https://github.com/leavesC/Dagger2Samples)
140-
* [Gson 使用详解](notes/AndroidGson使用详解.md)
140+
* [Gson 使用详解](notes/AndroidGson使用详解.md)
141141

142142
* [Android 自定义View基础](https://github.com/leavesC/JavaKotlinAndroidGuide)
143143
* [Android View 事件分发机制详解](other/Android事件分发机制详解.md)
@@ -165,9 +165,9 @@ Android 章节的内容包括:四大组件、权限系统、官方框架、自
165165
* [Android 多线程之HandlerThread源码解析](multithreading/Android多线程之HandlerThread源码解析.md)
166166
* [Android 多线程之IntentService源码解析](multithreading/Android多线程之IntentService源码解析.md)
167167
* [Android 多线程之AsyncTask源码解析](multithreading/Android多线程之AsyncTask源码解析.md)
168-
* [Android HandlerThread 源码详细注释](sourceCode/HandlerThread.java)
169-
* [Android IntentService 源码详细注释](sourceCode/IntentService.java)
170-
* [Android AsyncTask 源码详细注释](sourceCode/AsyncTask.java)
168+
* [Android HandlerThread 源码详细注释](multithreading/HandlerThread.java)
169+
* [Android IntentService 源码详细注释](multithreading/IntentService.java)
170+
* [Android AsyncTask 源码详细注释](multithreading/AsyncTask.java)
171171

172172
* [Android IPC 机制](https://github.com/leavesC/JavaKotlinAndroidGuide)
173173
* [AndroidIPC机制(1)-进程和线程](https://github.com/leavesC/IPCSamples)

‎multithreading/Android多线程之AsyncTask源码解析.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
> 本系列文章会陆续对 Android 的多线程机制进行整体介绍,帮助读者了解 Android 环境下如何实现多线程编程,也算是对自己所学内容的一个总结归纳
2+
>
3+
> 项目主页:https://github.com/leavesC/JavaKotlinAndroidGuide
4+
>
5+
16
AsyncTask 是一个较为轻量级的异步任务类,在底层通过封装 ThreadPool 和 Handler ,实现了线程的复用,后台任务执行顺序的控制、子线程和 UI 线程的切换,使得开发者可以以简单的方法来执行一些耗时任务
27

38
此篇文章就基于 Android API 27 版本的源码来对 AsyncTask 进行一次整体分析,以便对其底层工作流程有所了解
@@ -341,6 +346,6 @@ AsyncTask 是一个较为轻量级的异步任务类,在底层通过封装 Thr
341346
}
342347
```
343348

344-
**以上就是 AsyncTask 较为关键的几个点,看过后应该就能明白 AsyncTask 的整体工作流程了,如果需要 AsyncTask 更为详细的源码注释,可以看这里:[AsyncTask](https://github.com/leavesC/Java_Android_Learn/blob/master/Java_Android_Learn/sourceCode/AsyncTask.java)**
345349

346-
**更多的源码解读请看这里:[Java_Android_Learn](https://github.com/leavesC/Java_Android_Learn)**
350+
351+
**更多的源码解读请看这里:[JavaKotlinAndroidGuide](https://github.com/leavesC/JavaKotlinAndroidGuide)**

‎multithreading/Android多线程之HandlerThread源码解析.md‎

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
> 想要了解 HandlerThread 的工作原理需要先对 Android 系统中以 Handler、Looper、MessageQueue 组成的异步消息处理机制有所了解,如果你还没有这方面的知识,可以先看我写的另一篇文章:[Handler、Looper与MessageQueue源码解析](./Android多线程之Handler、Looper与MessageQueue源码解析.md)
1+
> 本系列文章会陆续对 Android 的多线程机制进行整体介绍,帮助读者了解 Android 环境下如何实现多线程编程,也算是对自己所学内容的一个总结归纳
2+
>
3+
> 项目主页:https://github.com/leavesC/JavaKotlinAndroidGuide
4+
>
5+
> 想要了解 HandlerThread 的工作原理需要先对 Android 系统中以 Handler、Looper、MessageQueue 组成的异步消息处理机制有所了解,如果你还没有这方面的知识,可以先看我写的另一篇文章:[Handler、Looper与MessageQueue源码解析](https://github.com/leavesC/JavaKotlinAndroidGuide/blob/master/multithreading/Android多线程之Handler、Looper与MessageQueue源码解析.md)
26
37
#### 一、概述
48

@@ -15,14 +19,14 @@
1519

1620
创建 HandlerThread 并调用 `start()` 方法,使其在子线程内创建 Looper 对象
1721

18-
```
22+
```java
1923
HandlerThread handlerThread = new HandlerThread("HandlerThread");
2024
handlerThread.start();
2125
```
2226

2327
然后以 HandlerThread 内部的 Looper 对象为参数创建一个 Handler,通过 Handler 向子线程发送 Message,以此下发耗时任务,消息的接收者与任务的处理者则由回调函数 ChildCallback 来完成
2428

25-
```
29+
```java
2630
Handler childThreadHandler = new Handler(handlerThread.getLooper(), new ChildCallback());
2731

2832
//Callback 运行于子线程
@@ -114,9 +118,7 @@ public class MainActivity extends AppCompatActivity {
114118

115119
#### 三、源码分析
116120

117-
先看下 HandlerThread 的类声明
118-
119-
Thread 的子类
121+
先看下 HandlerThread 的类声明,是 Thread 的子类
120122

121123
```java
122124
public class HandlerThread extends Thread
@@ -162,7 +164,7 @@ Thread 的子类
162164
}
163165
```
164166

165-
`Looper.prepare()` 方法用于为当前线程创建一个 Looper 对象,在主线程需要依赖此 Looper 对象来构建一个 Handler 对象,通过该 Handler 对象来向子线程下发耗时任务(这些知识点可以在这里了解:[Handler、Looper与MessageQueue源码解析](./Android多线程之Handler、Looper与MessageQueue源码解析.md))
167+
`Looper.prepare()` 方法用于为当前线程创建一个 Looper 对象,在主线程需要依赖此 Looper 对象来构建一个 Handler 对象,通过该 Handler 对象来向子线程下发耗时任务
166168

167169
之后可以看到有一个同步代码块,在当中调用了 `notifyAll()`来唤醒等待线程,那该唤醒的又是哪个线程呢?这里需要明确各个方法是运行于哪个线程,`run()` 方法肯定是运行于子线程,但用于向 HandlerThread 下发任务的 Handler 是初始化于主线程,因此 `getLooper()`方法也是运行于主线程的。由于是两个不同的线程,`run()` 方法和 `getLooper()` 的运行先后顺序是不明确的,因此 `getLooper()` 方法需要确保 Looper 对象不为 **null** 时才返回,否则将一直阻塞等待 Looper 对象初始化完成
168170

@@ -316,4 +318,6 @@ public class HandlerThread extends Thread {
316318
}
317319
```
318320

319-
**更多的源码解读请看这里:[Java_Android_Learn](https://github.com/leavesC/Java_Android_Learn)**
321+
322+
323+
**更多的源码解读请看这里:[JavaKotlinAndroidGuide](https://github.com/leavesC/JavaKotlinAndroidGuide)**

‎multithreading/Android多线程之Handler、Looper与MessageQueue源码解析.md‎

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1+
> 本系列文章会陆续对 Android 的多线程机制进行整体介绍,帮助读者了解 Android 环境下如何实现多线程编程,也算是对自己所学内容的一个总结归纳
2+
>
3+
> 项目主页:https://github.com/leavesC/JavaKotlinAndroidGuide
4+
15
本文的目的是来分析下 Android 系统中以 Handler、Looper、MessageQueue 组成的异步消息处理机制,通过源码来了解整个消息处理流程的走向以及相关三者之间的关系
26

3-
需要先了解以下几个预备知识
7+
需要先了解以下几个基本概念
8+
9+
- Handler:主线程或者子线程通过 Handler 向 MessageQueue(消息队列) 发送 Message,以此来触发定时任务或者更新 UI
10+
- MessageQueue:通过 Handler 发送的消息并非是立即执行的,需要存入消息队列中来依次执行,消息队列中的任务依照消息的优先级高低(延时时间的长短)来顺序存放
11+
- Looper:Looper 用于从 MessageQueue 中循环获取消息并将之传递给消息处理者(即消息发送者 Handler 本身)来进行处理,每条 Message 都有个 target 变量用来指向消息的发送者本身,以此把 Message 和其处理者关联起来
12+
- 互斥机制:可能会有多条线程(1条 UI 线程,n 条子线程)同时向同一个消息队列插入消息,此时就需要有同步机制来保证消息的有序性以避免竞态
413

5-
- Handler:UI 线程或者子线程通过 Handler 向 MessageQueue(消息队列) 发送 Message
6-
- MessageQueue:通过 Handler 发送的消息并非是立即执行的,需要存入一个消息队列中来依次执行
7-
- Looper:Looper 不断从 MessageQueue 中获取消息并将之传递给消息处理者(即是消息发送者 Handler 本身)进行处理
8-
- 互斥机制:可能会有多条线程(1条 UI 线程,n 条子线程)向同一个消息队列插入消息,此时就需要进行同步
14+
先从开发者日常的使用方法作为入口,以此来分析其整个流程的走向
915

10-
Handler 发送消息的形式主要有以下几种形式,其最终调用的都是 `sendMessageAtTime()` 方法
16+
Handler 发送消息的形式主要有以下几个方法,不管其是否是延时任务,其最终调用的都是 `sendMessageAtTime()` 方法
1117

1218
```java
1319
public final boolean sendMessage(Message msg){
@@ -26,7 +32,7 @@ Handler 发送消息的形式主要有以下几种形式,其最终调用的都
2632
}
2733
```
2834

29-
可以看到 `sendMessageAtTime()` 方法中需要一个已初始化的 `MessageQueue` 类型的全局变量 `mQueue`,否则程序无法继续走下去
35+
`sendMessageAtTime()` 方法中需要一个已初始化的 `MessageQueue` 类型的全局变量 `mQueue`,否则程序无法继续走下去
3036

3137
```java
3238
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
@@ -187,7 +193,7 @@ Handler 发送消息的形式主要有以下几种形式,其最终调用的都
187193
}
188194
```
189195

190-
因为存在多个线程往同一个 Loop 线程的 MessageQueue 中插入消息的可能,所以 `enqueueMessage()` 内部需要进行同步。可以看出 MessageQueue 内部是以链表的结构来存储 Message 的(**Message.next**),根据 Message 的延时时间的长短来将决定其在消息队列中的位置
196+
因为存在多个线程同时往同一个 Loop 线程的 MessageQueue 中插入消息的可能,所以 `enqueueMessage()` 内部需要进行同步。可以看出 MessageQueue 内部是以链表的结构来存储 Message 的(**Message.next**),根据 Message 的延时时间的长短来将决定其在消息队列中的位置
191197

192198
**mMessages** 代表的是消息队列中的第一条消息,如果 mMessages 为空,说明消息队列是空的,或者 mMessages 的触发时间要比新消息晚,则将新消息插入消息队列的头部;如果 mMessages 不为空,则寻找消息列队中第一条触发时间比新消息晚的非空消息,并将新消息插到该消息前面
193199

@@ -488,13 +494,14 @@ boolean enqueueMessage(Message msg, long when) {
488494

489495
最后来总结下以上的内容
490496

491-
一、在创建 Handler 实例时要么为构造函数提供一个 Looper 实例,要么默认使用当前线程关联的 Looper 对象,如果当前线程没有关联的 Looper 对象,则会导致抛出异常
497+
1. 在创建 Handler 实例时要么为构造函数提供一个 Looper 实例,要么默认使用当前线程关联的 Looper 对象,如果当前线程没有关联的 Looper 对象,则会导致抛出异常
498+
499+
2. Looper 与 Thread ,Looper 与 MessageQueue 都是一一对应的关系,在关联后无法更改,但 Handler 与 Looper 可以是多对一的关系
492500

493-
二、Looper 与 Thread ,Looper 与 MessageQueue 都是一一对应的关系,在关联后无法更改,但 Handler 与 Looper 可以是多对一的关系
501+
3. Handler 能用于更新 UI 有个前提条件:Handler 与主线程关联在了一起。在主线程中初始化的 Handler 会默认与主线程绑定在一起,所以此后在处理 Message 时,`handleMessage(Message msg)` 方法的所在线程就是主线程,因此 Handler 能用于更新 UI
494502

495-
三、Handler 能用于更新 UI 有个前提条件:Handler 与主线程关联在了一起。在主线程中初始化的 Handler 会默认与主线程绑定在一起,所以此后在处理 Message 时,`handleMessage(Message msg)` 方法的所在线程就是主线程,因此 Handler 能用于更新 UI
503+
4. 可以创建关联到另一个线程 Looper 的 Handler,只要本线程能够拿到另外一个线程的 Looper 实例
496504

497-
四、可以创建关联到另一个线程 Looper 的 Handler,只要本线程能够拿到另外一个线程的 Looper 实例
498505

499506
```java
500507
new Thread("Thread_1") {
@@ -520,4 +527,6 @@ boolean enqueueMessage(Message msg, long when) {
520527
}.start();
521528
```
522529

523-
**更多的源码解读请看这里:[Java_Android_Learn](https://github.com/leavesC/Java_Android_Learn)**
530+
531+
532+
**更多的源码解读请看这里:[JavaKotlinAndroidGuide](https://github.com/leavesC/JavaKotlinAndroidGuide)**

‎multithreading/Android多线程之IntentService源码解析.md‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
> 本系列文章会陆续对 Android 的多线程机制进行整体介绍,帮助读者了解 Android 环境下如何实现多线程编程,也算是对自己所学内容的一个总结归纳
2+
>
3+
> 项目主页:https://github.com/leavesC/JavaKotlinAndroidGuide
4+
>
15
> 想要了解 IntentService 的工作原理需要先对 Android 系统中以 Handler、Looper、MessageQueue 组成的异步消息处理机制以及 HandlerThread 有所了解,如果你还没有这方面的知识,可以先看我写的另外两篇文章:
26
>
3-
> [Handler、Looper与MessageQueue源码解析](./Android多线程之Handler、Looper与MessageQueue源码解析.md)
7+
> [Handler、Looper与MessageQueue源码解析](https://github.com/leavesC/JavaKotlinAndroidGuide/blob/master/multithreading/Android多线程之Handler、Looper与MessageQueue源码解析.md)
48
>
5-
> [Android 多线程之 HandlerThread 源码解析](./Android多线程之HandlerThread源码解析.md)
9+
> [Android 多线程之 HandlerThread 源码解析](https://github.com/leavesC/JavaKotlinAndroidGuide/blob/master/multithreading/Android多线程之HandlerThread源码解析.md)
610
711
在介绍 Service 时我们经常会说 Service 适合于完成一些在后台工作的任务,例如播放音乐、下载文件等,但 Service 默认是运行于 UI 线程的,如果想要依靠其来完成一些耗时任务,就需要自己来建立子线程,这相对比较繁琐,所以官方也为开发者提供了 IntentService 来解决这一问题
812

@@ -274,4 +278,6 @@ public abstract class IntentService extends Service {
274278
}
275279
```
276280

277-
**更多的源码解读请看这里:[Java_Android_Learn](https://github.com/leavesC/Java_Android_Learn)**
281+
282+
283+
**更多的源码解读请看这里:[JavaKotlinAndroidGuide](https://github.com/leavesC/JavaKotlinAndroidGuide)**

0 commit comments

Comments
 (0)