Android基础知识之多线程
1、为什么使用多线程
-
防止ANR
- 什么是ANR(Application Not Responding)
- 主线程阻塞
- Activity的最长执行时间是5秒
- BroadcastReceiver的最长执行时间是10秒
- Activity Manager/Window Mangager Service 监视
-
提高用户体验
- 上传/下载文件时
- 大文件读取/写入时
- 其他的耗时操作
2、多线程的实现方法
- Java标准多线程
- 继承Thread
- Thread&Runnable
- 线程的基本操作
- 启动线程start
- 睡眠sleep
- 设置优先级setPriority
- 中断interrupt
- 等待线程结束join
- 线程间的协作
- wait
- notify
- notifyAll
-
Java标准多线程
- 线程生命周期
- 线程生命周期
- 创建状态
- 当用new操作符创建的线程只是一个空的线程对象,该线程处于创建状态
- 处于创建状态的线程只是一个空的线程对象,系统不为它分配资源
- 可运行状态
- 执行线程的start() 方法将为线程分配必须的系统资源,安排其运行,并调用线程体——run() 方法,这样就使得该线程处于可运行 (Runnable) 状态
- 这一状态并不是运行中状态 (Running) ,因为线程也许实际上并未真正运行
- 不可运行状态
- 当发生下列时间是,处于运行状态的线程会转入到不可运行状态
- 调用了sleep() 方法
- 线程调用了wait 方法等待特定条件的满足
- 线程输入/输出阻塞
- 返回可运行状态
- 处于睡眠状态的线程在指定的时间过去后
- 如果线程在等待某一条件,另一个对象必须通过notify() 或 notifyAll() 方法通知等待线程条件的改变
- 如果线程是因为输入/输出阻塞,等待输入/输出完成
- 消亡状态
- 当线程的run方法执行结束后,该线程自然消亡
- 创建状态
- 注意事项
- 停止线程的方式: 不能使用
Thread
类的stop
方法来终止线程的执行,一般要设定一个变量,在run
方法中是一个循环,循环每次检查该变量,如果满足条件则继续执行,否则跳出循环,线程结束。
- 停止线程的方式: 不能使用
- 死锁问题
- 一般造成死锁必须同时满足如下4个条件:
- 互斥条件:线程使用的资源必须至少有一个是不能共享的
- 请求与保持条件:至少有一个线程必须持有一个资源并且正在等待获取一个当前被其他线程持有的资源
- 非剥夺条件:分配资源不能从相应的线程中被强制剥夺
- 循环等待条件:第一个线程等待其他线程,后者又在等待第一个线程
- 因为要产生死锁,这4个条件必须同时满足,所以要防止死锁的话,只需要破坏其中一个条件即可
- 一般造成死锁必须同时满足如下4个条件:
- 线程生命周期
3、线程间通信
-
Message
- 用来定义发送到Handler的任意类型的数据
- 通常情况下,使用额外的2个int类型的Field就足够了
- 使用Message.obtain()或Handler.obtainMessage()创建
-
Handler
- 用来发送处理Message和Runnable
- 跟创建Handler的线程及其Message Queue关联,Handler在该线程中运行
- 用途:
- 定时运行
- 在另一个线程执行
-
Handler与Looper
- Handler必须跟Looper联系在一起
- 主线程已经有默认的Looper
- 子线程需要自己的Looper
-
HandlerThread
- Thread with Looper
- 使用Looper之前必须先启动线程
4、 线程安全
- 问题
- 访问同一个资源
- 代码临界区
- Android UI不是线程安全的
- 解决方案
- wait()
- 使用
synchronized
关键字- sychronized method(){}
- sychronized (objectReference) {/block/}
- static synchronized method(){}
- sychronized(classname.class)
- 用主线程的Handler访问UI
- 用runOnUiThread()访问UI