【Android】线程与线程池

一、线程

 在Android系统中,线程分为主线程与子线程,众所周知,主线程主要处理和UI相关的操作,而子线程则用于处理耗时的操作,除了Thread外,扮演线程角色的还有AsyncTask、IntentService和HandlerThread等。AsyncTask封装了线程池和Handler,主要是为了方便开发者在子线程中更新UI;HandlerThread是一个消息循环的线程,其内部可以使用Handler;IntentService是一个服务,系统对其封装后使其更加方面的执行后台操作,使用了HandlerThread来执行任务。

1、AsyncTask

 AsyncTask是一个轻量的异步任务类,它主要是在线程池中执行后台任务,然后把执行的进度和结果传递给主线程中并更新UI,由于AsyncTask的设计初衷是为了执行简单的后台任务,并在主线程中快速更新UI和默认的串行执行方式(在Android1.6前是串行执行,在Android1.6改为并行执行,但是为了避免并行执行带来的错误,在Android3.0时又将AsyncTask改回串行执行,但是提供了executeOnExecutor方法执行并行任务)使得AsyncTask并不适合执行耗时的操作。
 AsyncTask是一个抽象的泛型类,有params、progress和result三个参数,分别表示参数的类型、后台任务的执行进度的类型、后台任务返回结果的类型。主要的方法有四个:onPreExecute、onPostExecute、onProgressUpdate和doInBackground。

 private class DownloadAsyncTask extends AsyncTask<Void, Void, Void >{
        @Override
        protected void onPreExecute() {     //准备工作
            super.onPreExecute();
        }

        @Override 
        protected void onPostExecute(Void aVoid) {    //任务完成后执行的方法(在主线程中)
            super.onPostExecute(aVoid);
        }

        @Override
        protected void onProgressUpdate(Void... values) {   //任务执行中,更新进度的方法(在主线程中)
            super.onProgressUpdate(values);
        }

        @Override
        protected Void doInBackground(Void... voids) {   //在后台执行任务的方法(在子线程中)
            return null;
        }
    }
 DownloadAsyncTask downloadAsyncTask = new DownloadAsyncTask();  //在主线程中创建
 downloadAsyncTask.execute();//串行执行
 downloadAsyncTask.executeOnExecutor(executor);  //并行执行

 在AsyncTask的使用过程有如下注意事项:
 1、AsyncTask的对象必须在主线程中创建
 2、execute方法必须在UI线程中调用
 3、不能直接调用onPreExecute、onPostExecute、onProgressUpdate和doInBackground等方法。
 4、一个AsyncTask对象只能调用一次execute方法。

2、HandlerThread

 HandlerThread继承了Thread,是一种可以使用Handler的Thread,在run方法中通过looper.prepare()方法创建了消息队列,并通过Looper.loop()开启了消息循环,因此可以创建一个Handler,并通过Handler的消息方式来通知HandlerThread执行一个具体的任务。

3、IntentService

 IntentService是一种特殊的Service,继承了Service并且是它的一个抽象类,因此必须创建它的子类才能使用IntentService。IntentService封装了HandlerThread和Handler,当第一次启动时,onCreate方法会被调用,并创建一个HandlerThread,然后它的looper构建了一个Handler对象mServiceHandler。随后每次启动,IntentService方法就会被调用。IntentService的创建:

private class IntentService extends android.app.IntentService{

        public IntentService(String name) {
            super(name);
        }

        @Override
        protected void onHandleIntent(@Nullable Intent intent) {

        }
    }

IntentService与Service的区别:
1、service与应用程序在同一个进程中,同时没有创建新线程的操作,如果执行耗时任务,仍需手动创建新线程
2、IntentService使用队列的方式将请求的Intent加入队列,然后开启了一个Worker Thread(工作线程)在处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后在处理第二个,每一个请求都会在一个单独的Worker Thread中处理,不会阻塞应用程序的主线程。

二、线程池

 线程池优点:
 1、重用线程池中的线程,避免因线程的创建和销毁所带来的性能开销
 2、能有效控制线程池的最大并发数,避免大量线程之间因相互抢占系统资源而导致的阻塞现象。
 3、能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。

1、ThreadPoolExecutor

 由于Android线程池都是直接或者间接通过配置ThreadPoolExecutor来实现,因此简单介绍一下ThreadPoolExecutor。在ThreadPoolExecutor的构造方法中有如下参数:

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

①corePoolSize
 线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使处于闲置状态。如果设置allowCoreThreadTimeOut为true,那么闲置的核心线程就有一个超时策咯,该超时由keepAliveTime所指定,超时后,该核心线程会被终止。

②maximumPoolSize:线程池能容纳的最大线程数,当活动线程数超过该值,后续线程会被阻塞

③keepAliveTime:非核心线程闲置的超时时长

④unit:指定keepAliveTime的时间单位

⑤workQueue:线程池中的任务队列

⑥threadFactory:线程工厂,为线程池提供创建新线程的功能

2、线程池分类

1、FixedThreadPool
 一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。只有核心线程,且核心线程不会被回收,因此能哈快速相应外界请求。没有超时机制、任务队列没有大小限制。

2、CachedThreadPool
 线程数量不定、只有非核心线程,最大线程数为Integer.Max_VALUE,消息队列是一个空集合,导致任何任务都可以立即被执行。综上,该线程池比较适合执行大量的耗时少的任务。

3、ScheduledThreadPool
 核心线程数量是固定的,非核心线程数量是没有限制的,当非核心线程闲置时会被立即回收,主要用于执行定时任务和具有固定周期的重复任务。

4、SingleThreadExecutor
 只有一个核心线程,所有任务都在同一个线程中按顺序执行,不需要处理线程同步的问题。

部分内容参考自:《Android开发艺术探索》

猜你喜欢

转载自blog.csdn.net/J675620982/article/details/81510483