android 线程和线程池
线程
一、简介
线程是CPU调度的最小单位。当一个程序第一次启动的时候,Android 会启动一个 Linux 进程和一个主线程。Android 中所有的组件都在主线程中实例化。主线程主要负责处理 UI 相关的事件,所以又被叫做 UI 线程。在 Android 中主线程是不能够做耗时操作的,子线程是不能够更新UI的。
与进程的区别:
二、创建多线程
2.1 继承 Thread 类
优点:实现简单,只要继承 Thread 类,并重写 run 方法就可以实现多线程。
缺点:
- 不适合资源共享。一个线程等于一个实例,相对独立,没办法进行资源共享;
- 消耗资源。Thread 线程相当于一次性消耗品,一个线程等于一个耗时任务,1个耗时任务执行完毕,线程会自动销毁。有100个耗时任务,就需要开启100个线程。多次创建和销毁十分消耗系统资源。
具体使用:
// 步骤1:创建线程类 (继承自Thread类) class MyThread extends Thread{ @Override public void run(){ // 步骤2:从写run方法 } } // 步骤3:创建线程对象,即 实例化线程类 MyThread mt=new MyThread(“线程名称”); // 步骤4:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止 mt.start();
可复用,代码量大
使用匿名类:
new Thread("线程名称") { @Override public void run() { // doSomeThing }.start();
不可复用,简介
注意:Thread 调用 run() 方法,就是一个普通的方法,失去线程的特性;start() 方法才会启动一个线程。
2.2 实现Runnable接口
优点:
- 适合资源共享。Runnable 的代码可以被多个线程(Thread 实例)共享,适合多个线程共同处理同一资源的情况;
- 灵活。一个类可以继承多个接口,避免了继承 Thread 的单继承局限性。
Java中真正能创建新线程的只有Thread类对象。通过实现Runnable的方式,最终还是通过Thread类对象来创建线程。所以对于实现了Runnable接口的类,称为线程辅助类;Thread类才是真正的线程类。
具体使用:
// 步骤1:创建线程辅助类,实现Runnable接口 class MyRunnable implements Runnable{ @Override // 步骤2:复写run(),定义线程行为 public void run(){ } } // 步骤3:创建线程辅助对象,即 实例化 线程辅助类 MyRunnable mr=new MyRunnable(); // 步骤4:创建线程对象,即 实例化线程类;线程类 = Thread类;创建时通过Thread类的构造函数传入线程辅助类对象 Thread td=new Thread(mr); // 步骤5:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止 td.start();
使用匿名类:
Runnable mt = new Runnable() { @Override public void run() { } }; Thread mt1 = new Thread(mt, "窗口1"); mt1.start();
2.3 AsyncTask
作用:
实现工作线程 & 主线程(UI线程)之间的通信,即:将工作线程的执行结果传递给主线程,从而在主线程中执行相关的UI操作。从而保证线程安全。
优点:
- 方便实现异步通信。不需使用 “任务线程(如继承Thread类) + Handler”的复杂组合;
- 节省资源。采用线程池的缓存线程 + 复用线程,避免了频繁创建 & 销毁线程所带来的系统资源开销。
缺点:
- 线程是串行执行的(即后台只有一个线程);
虽然 AsyncTask 的任务执行是通过线程池,线程池的核心线程,非核心线程规格大于1,但是后台运行的线程也只有一个,这是因为 AsyncTask 的任务管理线程池是 串行的 即,执行完一个任务才会执行下一个任务。
- 存在内存泄漏的风险。
类定义:
public abstract class AsyncTask<Params, Progress, Result> { ... } // 类中参数为3种泛型类型 // 整体作用:控制AsyncTask子类执行线程任务时各个阶段的返回类型 // 具体说明: // a. Params:开始异步任务执行时传入的参数类型,对应excute()中传递的参数 // b. Progress:异步任务执行过程中,返回下载进度值的类型 // c. Result:异步任务执行完成后,返回的结果类型,与doInBackground()的返回值类型保持一致 // 注: // a. 使用时并不是所有类型都被使用 // b. 若无被使用,可用java.lang.Void类型代替 // c. 若有不同业务,需额外再写1个AsyncTask的子类 }
AsyncTask 核心 & 常用的方法如下:
使用步骤:
- 创建 AsyncTask 子类 & 根据需求实现核心方法
- 创建 AsyncTask子类的实例对象(即 任务实例)
- 手动调用execute(()从而执行异步线程任务。同一个AsyncTask实例对象只能执行1次,若执行第2次将会抛出异常
注意:
- AsyncTask 是基于线程池进行实现的,当一个线程没有结束时,后面的线程是不能执行的。同时,AsyncTask 不与任何组件绑定生命周期,在Activity 或 Fragment中使用 AsyncTask时,最好在Activity 或 Fragment的 onDestory 方法里面调用 cancel(boolean);
if (myAsyncTask != null && myAsyncTask.getStatus() == Status.RUNNING) { //cancel方法只是将对应的AsyncTask标记为cancelt状态,并不是真正的取消线程的执行. myAsyncTask.cancel(true); }
- 若 AsyncTask 被声明为 Activity 的非静态内部类,当 Activity 需销毁时,会因 AsyncTask 保留对 Activity 的引用而导致 Activity 无法被回收,最终引起内存泄露。AsyncTask 应被声明为静态内部类;
- 当 Activity 重新创建时(屏幕旋转 / Activity被意外销毁时后恢复),之前运行的 AsyncTask(非静态的内部类)持有的之前Activity 引用已无效,故复写的 onPostExecute() 将不生效,即无法更新UI操作。所以,在 Activity 恢复时的对应方法需要重启任务线程。
- cancel 方法被调用后,onPostExecute和onProgressUpdate方法都不会再调用了。而doInBackground方法却会一直执行下去,也就是后台任务会继续执行。所以,cancel 并不是真正的取消,只是改变了标志状态,断开了和主线程之间的联系。真正的取消需要在doInBackground里面操作。
- 调用 execute 启动线程是串行的(1任务执行完才会执行2任务...)。那如何让任务并行执行呢,如下:
// AsyncTask 自带的线程池 task1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); task2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); // MY_THREAD_POOL_EXECUTOR 为自定义的线程池 task1.executeOnExecutor(MY_THREAD_POOL_EXECUTOR); task2.executeOnExecutor(MY_THREAD_POOL_EXECUTOR); // 替换掉默认的 AsyncTask.SERIAL_EXECUTOR MyAsyncTask.setDefaultExecutor(MY_THREAD_POOL_EXECUTOR); new MyAsyncTask(mActivity, "Task#a ").execute("abc"); new MyAsyncTask(mActivity, "Task#b ").execute("abc");
demo连接:处理了AsyncTask串行、并行问题,自定义线程池,以及AsyncTask内存泄漏的问题
原理:
参考原文:Android 多线程:AsyncTask的原理 及其源码分析
线程池
Carson_Ho的原文地址:Android多线程:线程池ThreadPool 全面解析
相关推荐
zzqLivecn 2020-07-09
xilove0 2020-07-09
瓜牛呱呱 2020-11-12
starinshy 2020-11-10
farewellpoem 2020-11-09
Charlesbases 2020-10-23
arctan0 2020-10-14
hackerlpy 2020-09-25
温攀峰 2020-09-16
天空一样的蔚蓝 2020-09-04
ericxieforever 2020-09-03
cyhgogogo 2020-08-18
大唐帝国前营 2020-08-18
yuanlu 2020-08-17
deepSTEM 2020-08-16
chunjiekid 2020-08-16
lhtzbj 2020-08-13
shonmark 2020-08-03
cuiweisaidelike 2020-08-02