Android线程与线程池

    xiaoxiao2021-03-25  96

    一. 线程分类

    线程主要分为主线程跟子线程。

    主线程 主线程,也叫UI线程。主要处理界面交互的逻辑。我们不能在主现场中执行耗时操作,因为这样会造成界面卡顿,用户体验不好,甚至会引起ANR,导致应用崩溃。

    子线程 子线程,也叫工作线程,主要处理主线程不能处理的耗时操作,比如网络请求,数据库操作,IO操作。

    二. 线程表现形式

    在Android中,线程的承载形式主要有Thread,AsynTask,IntentServices,HandleThred。

    1.AsynTask

    AsynTask是一个轻量级执行异步任务的类,主要作用就是在后台执行耗时任务,然后把耗时的任务到进度跟返回值反馈到主线,让主线做相应的UI更新操作。它底层使用的是Thred跟Handler。

    1.1 AsynTask的基本使用

    AsynTask是一个抽象的泛型类它提供了Params,Progress,Result三个泛型参数。

    public abstract class AsyncTask<Params, Progress, Result>

    Params:表示AsynTask执行异步任务的时候的参数类型,比如下载文件的时候的UrlProgress:后台执行任务的进度类型Result:后台执行任务完成返回的结果类型

    AsynTask一般需要重写四个方法 onPreExecute():在执行异步任务的之前会调用,用于前期准备工作。

    doInBackground(Params…params):用于执行异步任务

    onProgressUpdate(Progress…progress):当异步任务的进度发生变化的时候调用。注意:这个方法不会自动执行,需要手动在 doInBackground方法里面通过调用publishProgress方法,publishProgress才会调用onProgressUpdate方法更新进度,该方法是在主线程中执行。

    onPostExecute(Result result) :在异步任务执行完成之后,该方法就会被调用,result值就是doInBackground返回值。

    这个四个方法执行执行次序就是: onPreExecute->doInBackground->onProgressUpdate->onProgressUpdate

    2.HandlerThread

    HandlerThread是一个比较特殊的Thread类,让我们看看它一部分源码

    public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }

    通过源码,我们很容易得知它内部创建了消息队列。一般情况下,HandlerThread其中使用场景就是IntentServices。

    2.1 HandlerThread的简单使用

    HandlerThread mThread = new HandlerThread("线程名称"); mThread.start();

    注意:因为HandlerThread内部使用了Looper消息轮训,我们知道Looper的轮训是一个死循环,所以当我们不用HandlerThread的时候需要手动去通过Looper的quiet或者quietSafely方法去停止它

    3.IntentService

    IntentService是Service的子类,它主要用于执行后台耗时任务,当任务执行完成之后,就会自动停止。它的好处就是当我们需要在后台执行耗时任务的时候,可以不用重新创建启动线程,当任务完成之后不用管理该服务的生命周期。它内部使用的Handler跟HandlerThread。

    3.1 IntentService简单实用

    通过继承IntentService抽象类,然后复写onHandleIntent,把耗时的任务写在onHandleIntent里面。 然后通过context.startService(intent) 启动服务即可。 举个例子:

    class DownloadFileServices extends IntentService{ public DownloadFileServices(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { downloadFile(); } }

    然后只要Activity启动服务就可以了

    三. 线程池

    当我们需要执行异步任务的时候,我们就会创建一个线程去实现,这样虽然很方便,如果过多创建线程的时候,就不可以避免的产生系统资源浪费的问题。如果需要解决这个问题,这时候就需要引入线程池了。线程池最主要作用就是重复使用线程,节省性能开销,同时还能对线程进行队列管理,防止线程之间互相抢占资源。

    3.1 线程池的实现类-ThreadPoolExecutor

    ThreadPoolExecutor实现线程池的实现类,构造函数中提供了一系列参数来配置线程池。

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

    下面讲解一下这些参数的含义: corePoolSize:线程池的核心线程数。如果allowCoreThreadTimeOut属性为false的情况,核心线程会一直存活在线程池。 maximumPoolSize:线程池能容纳的最大线程数量。 keepAliveTime:线程闲置的时候的超时时常。如果线程的属性allowCoreThreadTimeOut为true的时候,这个时间会作用于非核心线程跟核心线程,如果allowCoreThreadTimeOut为false的时候,这个时间只会作用于非核心线程。 unit:keepAliveTimed的时间单位 workQueue:线程池的任务队列。 threadFactory:线程工程,主要用于生产线程。 handler:线程无法执行任务的时候采用的策略。

    3.2 线程池处理任务的方式

    如果线程池中的核心线程未达到核心线程的数量,就会创建一个核心线程执行任务,如果核心线程数量已满,那么任务就被放入队列里面,直到队列任务也满了,才会创建非核心线程来处理任务。如果队列满了,线程数量也达到最大值,那么就会拒绝处理任务。

    3.3 线程池的队列

    ArrayBlockingQueue:基于数组的先进先出队列LinkedBlockingQueue:基于链表的先进先出队列SynchronousQueue:一个没有数据缓存区的阻塞队列,是一个比较特殊的队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态。DelayedWorkQueue: 基于二叉树的队列

    3.3 线程池的分类

    FixedThreadPool

    核心线程数:固定 非核心线程数:没有 超时时间:无限制 任务队列:LinkedBlockingQueue 队列限制数量:无限制

    CachedThreadPool

    核心线程数:没有 非核心线程数:没有 超时时间:60s 任务队列:SynchronousQueue 队列限制数量:无限制

    ScheduledThreadPool

    核心线程数:固定 非核心线程数:没有限制 超时时间:0s,一限制就马上被回收 任务队列:DelayedWorkQueue

    SignleThreadExecutor

    核心线程数:一个 非核心线程数:没有 超时时间:没有限制 任务队列:LinkedBlockingQueue 队列限制数量:无限制

    转载请注明原文地址: https://ju.6miu.com/read-16992.html

    最新回复(0)