目录
线程的定义
线程分两类
(1)主线程,又名UI线程,顾名思义就是处理绘制界面、响应用户操作的线程,不可处理耗时操作(导致线程安全和ANR问题),程序默认进入的是主线程
(2)子线程,又名work线程,就是处理耗时操作的线程,如网络请求,IO存取,音乐播放
创建线程的三种方式
1.Thread
run()线程执行操作
调用run()知识调用了该子线程的run方法,而调用子线程的start()才会创建新线程并回调run()
class MyThread:Thread(){
Override fun run() {
super.run();
Log.i(Thread.currentThread().getId());
}
}
fun main(){
MyThread().start()
}
2.Runnable
Runnable只是一个接口,不能创建新线程
这里是新建一个Thread线程,调用Runable接口的run()
class MyThread:Runnable{
Override fun run() {
Log.i("MyThread", Thread.currentThread().getName());
}
}
fun main{
MyThreaed myThread = new MyThread();
new Thread(myThread).start()
}
3.Callable
需要结合FutureTask,实现Callable接口的对象,再实例化Thread(FutureTask)
优点:
- Callable 接口下的方法是 call(),Runnable 接口的方法是 run();
- Callable 的任务执行后可返回值,而 Runnable 的任务是不能返回值的;
- call() 方法可以抛出异常,run()方法不可以的;
- 运行 Callable 任务可以拿到一个 Future 对象,表示异步计算的结果
class MyThread:Callable<Integer>{
Override fun call():Integer{
Log.i("MyThread", Thread.currentThread().getName());
return 0;
}
}
fun main(){
val myThread = MyThread()
val futureTask = FutureTask(myThread)
MyThread(futureTask).start()
}
线程的生命周期
线程通信工具类
1.FutureTask
- 弥补Thread设计缺陷,获取线程执行完成与完成后返回值
- 异步任务,实现了Runnable、Callable、Future接口
- FutureTask就是解决获取执行结果的问题
fun main(){
val futureTask = FutureTask(object:Callable<Int>{
Override fun call(){
//线程操作
return 0
}
})
MyThread(futureTask).start()
}
2.AsyncTask
- 轻量级的异步任务类
- 把子线程执行进度和结果传递给主线程并更新UI
- 三个泛型:Params(传递给异步任务执行前的参数)
Progress(任务执行时返回给UI线程表示进度的参数值)
Result(任务执行完毕后,返回给UI线程的结果)
结合上方相关方法总结图和下方相关方法实际运用
泛型分别为String,Integer,String
第一个String:启动任务的传入参数,比如Http请求的URL
Integer:异步任务的进度值
第三个String:任务执行完返回的结果
class MainActivity : AppCompatActivity() {
private lateinit var progressBar:ProgressBar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
progressBar = findViewById(R.id.progress)
}
inner class MyAsyncTask:AsyncTask<String,Int,String>(){
override fun onPreExecute() {
super.onPreExecute()
/**
* 执行异步任务前,初始化UI控件
*/
}
override fun doInBackground(vararg p0: String?): String {
//子线程耗时操作
publishProgress(进度值)
return "泛型第三个String,表示异步任务执行完毕,返回Result"
}
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
/**
* 回到UI主线程
* 获取doInBackground中通过publishProgress传递的进度值
* 子线程进度值就是这里传进来的参数
*/
if (values != null) progressBar.progress = values[0]!!
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
/**
* 回到UI主线程
* 异步任务执行完毕,返回结果作为参数
* 可以设置一些结尾UI操作
*/
}
}
}
3.HandlerThread
- 简化版"多线程+Handler"
- 当需要多线程并发执行多个任务
- 创建一个包含looper的线程(子线程默认没有Looper,每个线程最多一个Looper和MQ)
val mHandlerThread = HandlerThread("为HandlerThread取名").apply {
start()//开启子线程
}
val mHandler = object:Handler(mHandlerThread.looper){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
//处理接收到的消息
when(msg.what){
1-> println(msg.obj.toString())
else->{}
}
}
}
val msg = Message().apply {
what = 1
obj = "111"
mHandler.sendMessage(this)
}
4.IntentService
- 一个实现了HandlerThread的Service
- 好处:Service的优先级比较高,保证后台服务的优先正常执行
5.ThreadPoolExecutor
线程池需要传入以下参数:
- corePoolSize,线程池中核心线程的数量
- maximumPoolSize,线程池中的最大线程数
- keepAliveTime,非核心线程的超时时长
- unit,枚举时间单位
- workQueue,线程池中的任务队列
线程池的分配遵循这样的规则:
- 当线程池中的核心线程数量未达到最大线程数时,启动一个核心线程去执行任务;
- 如果线程池中的核心线程数量达到最大线程数时,那么任务会被插入到任务队列中排队等待执行;
- 如果在上一步骤中任务队列已满但是线程池中线程数量未达到限定线程总数,那么启动一个非核心线程来处理任务;
- 如果上一步骤中线程数量达到了限定线程总量,那么线程池则拒绝执行该任务,且ThreadPoolExecutor会调用RejectedtionHandler的rejectedExecution方法来通知调用者。
一般用法:
- shutDown(),关闭线程池,需要执行完已提交的任务;
- shutDownNow(),关闭线程池,并尝试结束已提交的任务;
- allowCoreThreadTimeOut(boolen),允许核心线程闲置,超时回收;
- execute(),提交任务无返回值;
- submit(),提交任务有返回值