Android 的线程和线程池

栏目: Android · 发布时间: 5年前

内容简介:在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制地产生,并且线程的创建和销毁都会有相应的开销。在 Android 中除了 Thread 以外,还有 AsyncTask、IntentService 以及 HandlerThread 都扮演着线程的角色。在 Java 中默认情况下一个进程只有一个线程,这个就是主线程,除主线程以外的线程都叫子线程,Android 沿用了同样的线程模型。AsyncTask 中有两个线程池(SerialExecutor 和 THREAD

在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制地产生,并且线程的创建和销毁都会有相应的开销。在 Android 中除了 Thread 以外,还有 AsyncTask、IntentService 以及 HandlerThread 都扮演着线程的角色。

主线程和子线程

Java 中默认情况下一个进程只有一个线程,这个就是主线程,除主线程以外的线程都叫子线程,Android 沿用了同样的线程模型。

Android 中的线程形态

AsyncTask

  1. AsyncTask 是一个轻量级的异步任务类,在线程池中执行后台任务,然后把进度和最终结果传递到主线程更新 UI。
  2. AsyncTask 是一个抽象的泛型类,提供了 ParamsProgressResult 三个泛型参数。如果不需要传递具体的参数,参数类型可以使用 Void 来代替。

    public abstract class AsyncTask <Params, Progress, Result>
    
  3. AsyncTask 提供 4 个核心方法:

    1. onPreExecute() :在主线程中执行,一般用于做一些准备工作。
    2. doInBackground(Params… params) :在线程池中执行异步任务,params 为输入参数。在此方法中可以调用 publishProgress(Progress) 方法来更新任务进度。最终需要返回结果给 onPostExecute 方法。
    3. onProgressUpdate(Progess… values) :在主线程中执行,任务进度更新时会调用此方法。
    4. onPostExecute(Result result) :在主线程中执行,result 为异步任务中返回的结果。
  4. AsyncTask 使用时的注意点:
    1. AsyncTask 的类必须在主线程中加载,这一过程在 Android 4.1 及以上版本被系统自动完成(ActivityThread 的 main 方法会调用 AsyncTask 的 init 方法)。
    2. AsyncTask 的对象必须在主线程中创建。
    3. execute 方法必须在 UI 线程中调用。
    4. 不要在程序中直接调用 onPreExecuteonPostExecutedoInBackgroundonProgressUpdate 方法。
    5. 一个 AsyncTask 对象只能执行一次,即只能调用一次 execute 方法,否则会报错。
    6. 在 Android 1.6 之前,AsyncTask 是串行执行任务的,Android 1.6 的时候开始采用线程池处理并行任务,但是从 Android 3.0 开始,又换回了串行执行任务的方式,不过我们可以通过 executeOnExecutor 方法执行并行任务。

AsyncTask 的工作原理

AsyncTask 中有两个线程池(SerialExecutor 和 THREAD_POOL_EXECUTOR)和一个 Handler(InternalHandler)。其中线程池 SerialExecutor 用于任务的排队,而线程池 THREAD_POOL_EXECUTOR 用于真正地执行任务,InternalHandler 用于将执行环境从线程池切换到主线程。

HandlerThread

  1. HandlerThread 继承了 Thread,它是一种可以使用 Handler 的 Thread。
  2. HandlerThread 的实现就是在其 run 方法中通过 Looper.prepare() 来创建消息队列,通过 Looper.loop() 来开启消息循环。
  3. HandlerThread 的 run 方法是一个无限循环,当不需要使用时,要通过 quit 或者 quitSafely 方法来终止线程。
  4. HandlerThread 的一个典型使用场景就是 IntentService。

IntentService

  1. IntentService 是一种特殊的抽象 Service,内部封装了 HandlerThread 和 Handler,比较适合执行一些高优先级的后台任务,不容易被杀死。

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
    
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    
  2. IntentService 调用 stopSelf(int startId) 方法来尝试停止服务,会等待所有消息都处理完毕后才真正终止服务。

  3. IntentService 的执行顺序是按外界发起的顺序去执行的。

Android 的线程和线程池

Android 中的线程池

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

ThreadPoolExecutor

ThreadPoolExecutor 常用构造方法如下:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory)
  • corePoolSize :线程池的核心线程数,默认情况下核心线程会一直存活。如果将 ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设置为 true,闲置时间超过 keepAliveTime 会被终止。
  • maximumPoolSize :线程池所能容纳的最大线程数(核心线程 + 非核心线程),当活动线程数达到这个数值后,后续任务会被阻塞。
  • keepAliveTime :非核心线程闲置时的超时时长,超过这个时长,非核心线程会被回收。当 ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设置为 true 时,同样作用于核心线程。
  • unit :指定 keepAliveTime 参数的时间单位。
  • workQueue :线程池中的任务队列,通过线程池的 execute 方法提交的 Runnable 对象会被存储在这个参数中。
  • threadFactory :线程工厂,为线程池提供创建新线程的功能。

ThreadPoolExecutor 执行任务时大致遵循如下规则:

  1. 如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
  2. 如果线程池中的线程数量达到或超过核心线程的数量,那么任务会被插入任务队列等待执行。
  3. 如果步骤2中无法将任务插入任务队列中,这往往是由于任务队列已满,这时如果线程数量未到达线程池规定的最大值,那么会立即启动一个非核心线程来执行任务。
  4. 如果步骤3中的线程数量已经达到了线程池规定的最大值,那么就会拒绝执行此任务。

线程池的分类

Android 中最常见的四类线程池都是通过 Executors 的静态方法创建的。

  1. FixedThreadPool- 线程数量固定的线程池,只有核心线程

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    
  2. CachedThreadPool- 线程数量不固定的线程池,只有非核心线程

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    
  3. ScheduledThreadPool- 核心线程数量固定,非核心线程数量没有限制的线程池,主要用于执行定时任务和具有固定周期的任务

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }
    
  4. SingleThreadExecutor- 只有一个核心线程的线程池,确保了所有的任务都在同一个线程中按顺序执行

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Scrum精髓

Scrum精髓

Kenneth Rubin / 姜信宝、米全喜、左洪斌、(审校)徐毅 / 清华大学出版社 / 2014-6-1 / CNY 79.00

短短几年时间,Scrum跃升为敏捷首选方法,在全球各地得以普遍应用。针对如何用好、用巧这个看似简单的框架,本书以通俗易懂的语言、条理清晰的脉络阐述和提炼出Scrum的精髓。全书共4部分23章,阐述了七大核心概念:Scrum框架,敏捷原则,冲刺,需求和用户故事,产品列表,估算与速率,技术债;三大角色:产品负责人,ScrumMaster,开发团队以及Scrum团队构成:Scrum规划原则及四大规划活动......一起来看看 《Scrum精髓》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试