Android线程池详解

      • 前言
      • ThreadPoolExecutor
      • 线程池的分类
        • FixedThreadPool
        • CachedThreadPool
        • ScheduledThreadPool
        • SingleThreadExecutor
      • 基本使用

前言

在开发中经常会使用到线程来进行异步操作,但是每个线程的创建和销毁都需要一定的开销。所以就需要线程池来对线程进行管理。Android中的线程池来源于Java中的Executor,Executor是一个接口,真正线程池实现类是ThreadPoolExecutor。

ThreadPoolExecutor

我们可以通过ThreadPoolExecutor来创建一个线程池,ThreadPoolExecutor有4个构造方法,它们提供了一系列参数来配置线程池。下面是ThreadPoolExecutor的一个参数最多的构造方法:

public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue workQueue,                              ThreadFactory threadFactory,                              RejectedExecutionHandler handler) {        if (corePoolSize < 0 ||            maximumPoolSize <= 0 ||            maximumPoolSize < corePoolSize ||            keepAliveTime < 0)            throw new IllegalArgumentException();        if (workQueue == null || threadFactory == null || handler == null)            throw new NullPointerException();        this.corePoolSize = corePoolSize;        this.maximumPoolSize = maximumPoolSize;        this.workQueue = workQueue;        this.keepAliveTime = unit.toNanos(keepAliveTime);        this.threadFactory = threadFactory;        this.handler = handler;    }

下边解释一下各个参数:

---------int corePoolSize

核心线程数。默认情况下线程池是空的,只有任务提交时才会创建线程。如果当前运行的线程数少于corePoolSize,则创建新线程来处理任务;如果等于或者大于corePoolSize,则不再创建。如果调用线程池的prestartAllcoreThread方法,线程池会提前创建并启动所有的核心线程来等待任务。

---------int maximumPoolSize

线程池允许创建的最大线程数。如果任务队列满了并且线程数小于maximumPoolSize时,则线程池仍旧会创建新的线程来处理任务。

---------long keepAliveTime

非核心线程闲置的超时时间。超过这个时间则回收。如果任务很多,并且每个任务的执行事件很短,则可以调大keepAliveTime来提高线程的利用率。另外,如果设置allowCoreThreadTimeOut属性为true时,keepAliveTime也会应用到核心线程上。

---------TimeUnit unit

用于指定keepAliveTime参数的时间单位。这是一个枚举,常用的有分钟(TimeUnit.MINUTES)、秒(TimeUnit.SECOND S)、毫秒(TimeUnit.MILLISECONDS)等。

---------BlockingQueue workQueue

任务队列。如果当前线程数大于corePoolSize,则将任务添加到此任务队列中。该任务队列是BlockingQueue类型的,也就是阻塞队列。

---------ThreadFactory threadFactory

线程工厂。为线程池提供创建新线程的功能,ThreadFactory是一个接口,它只有一个方法:Thread newThread(Runnable r);

---------RejectedExecutionHandler handler

饱和策略。这是当任务队列和线程池都满了时所采取的应对策略,默认是AbordPolicy,表示无法处理新任务,并抛出RejectedExecutionException异常。此外还有3种策略,它们分别如下:

1、CallerRunsPolicy:用调用者所在的线程来处理任务。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
2、DiscardPolicy:不能执行的任务,并将该任务删除。
3、DiscardOldestPolicy:丢弃队列最近的任务,并执行当前的任务。

ThreadPoolExecutor执行任务时遵循下面几个原则

(1)如果线程池中的线程数未达到核心线程数,则会创建一个核心线程来处理任务。
(2)如果线程数大于或者等于核心线程数,那么任务将会加入到任务队列中排队等待执行,线程池中的空闲线程会不断地从任务队列中取出任务进行处理。
(3)如果任务队列满了,并且这个时候线程数量没有达到最大线程数数量,那么会立刻启动一个非核心线程来处理任务。
(4)如果线程数超过了最大线程数,则执行饱和策略。ThreadPoolExecutor会调用RejectedExecutionHandler的rejected Execution方法来通知调用者。

线程池的分类

Android中有四类最常见的具有不同功能的线程池,它们通过直接或者间接地配置ThreadPoolExecutor的参数来实现自己的功能特性。

FixedThreadPool

FixedThreadPool通过Executors的newFixedThreadPool方法来创建,是一种线程数固定的线程池。当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue(),                                      threadFactory);    }

FixedThreadPool的corePoolSize和maximumPoolSize都设置为创建FixedThreadPool指定的参数nThreads,也就意味着FixedThreadPool只有核心线程,并且数量是固定的,没有非核心线程。由于FixedThreadPool只有核心线程并且这些核心线程不会被回收,这就意味着它能够更快速的地响应外界的请求。keepAliveTime设置为0L意味着多余的线程会被立即终止。因为不会产生多余的线程,所以keepAliveTime是无效的参数。另外,任务队列采用了无界的阻塞队列LinkedBlocking Queue。

CachedThreadPool

CachedThreadPool通过Executors的newCachedThreadPool方法来创建,是一种线程数不固定的线程池。

public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue());    }

CachedThreadPool的corePoolSize为0,maximumPoolSize设置为Integer.MAX_VALUE,这意味着CachedThreadPool没有核心线程,非核心线程是无界的。keepAliveTime设置为60L,则空闲线程等待新任务的最长时间为 60s。在此用了阻塞队列 SynchronousQueue,它是一个不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作,同样任何一个移除操作都等待另一个线程的插入操作。

ScheduledThreadPool

ScheduledThreadPool是一个能实现定时和周期性任务的线程池。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {        return new ScheduledThreadPoolExecutor(corePoolSize);    }

这里创建了ScheduledThreadPoolExecutor,ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,它主要用于给定延时之后的运行任务或者定期处理任务。构造方法如下:

public ScheduledThreadPoolExecutor(int corePoolSize) {        super(corePoolSize, Integer.MAX_VALUE,              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,              new DelayedWorkQueue());    }

ScheduledThreadPoolExecutor 的构造方法最终调用的是ThreadPoolExecutor的构造方法。corePoolSize是传进来的固定数值,maximumPoolSize的值是Integer.MAX_VALUE。因为采用的DelayedWorkQueue是无界的,所以maximumPoolSize这个参数是无效的。

SingleThreadExecutor

SingleThreadExecutor是使用单个工作线程的线程池。

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

corePoolSize和maximumPoolSize都为1,意味着SingleThreadExecutor只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。它的意义在于统一所有的外界任务到一个线程中,使这些任务之间不需要处理线程同步问题。其他的参数都和FixedThreadPool一样。

基本使用

下面代码简单介绍了四种线程池的基本使用:

Runnable task = new Runnable() {            @Override            public void run() {                //异步执行任务            }        };        ExecutorService pool1 = Executors.newFixedThreadPool(3);        pool1.execute(task);        ExecutorService pool2 = Executors.newCachedThreadPool();        pool2.execute(task);        ScheduledExecutorService pool3 = Executors.newScheduledThreadPool(4);        pool3.schedule(task, 1000, TimeUnit.MILLISECONDS);//1000m后执行task        pool3.scheduleAtFixedRate(task, 100, 1000, TimeUnit.MILLISECONDS);//延迟100ms后每隔1000ms执行一次task        ExecutorService pool4 = Executors.newSingleThreadExecutor();        pool4.execute(task);

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. Android(安卓)中文 API AsyncTask
  3. android核心技术与最佳实践笔记(一)
  4. Android学习之多线程编程(handler篇)
  5. Android由一个activity 间隔5秒自动跳转到另外一个activity
  6. Android性能优化典范(五)
  7. android display之VSync和线程处理关系
  8. ConditionVariable的用法
  9. Android实现TCP客户端接收数据的方法

随机推荐

  1. Android踩坑记Caused by: com.android.to
  2. Android 自动改 Hosts工具 v1.0.1 更
  3. (原创)如何导入android中的sample例子到ec
  4. android adapter的更新
  5. android一些常用事件
  6. Android SDK环境变量配置(windows和Linux
  7. 快速上手:Ophone及Android入门教程
  8. 【Android Linux内存及性能优化】(八) 系
  9. IOS之UITabBarViewController用法
  10. Android下实现一个Activity的全屏显示