参考链接
https://blog.csdn.net/u012702547/article/details/52259529
https://blog.csdn.net/wolf909867753/article/details/77500625

普通线程的劣势

通常,在Android中使用线程的话,基本使用new Thread来创建线程
例如

new Thread(new Runnable() {  @Override  public void run() {  //耗时操作 }  }).start();  

但是在Java中,创建线程是消耗资源的,频繁的创建和销毁线程是相当消耗资源的,为此,引入了线程池的概念。

线程池的优势

使用线程池可以指定并发线程数,可以控制线程延时启动,可以设定线程阻塞超时(超时后从等待队列移除)等等,可以更好的控制线程,而不像new Thread一样,无法管控
一般情况下,任务的执行,主要时间消耗在如下几个部分
1.线程创建时间T1 2.任务等待线程执行时间T2 3.线程执行任务时间T3 4.线程销毁时间T4
通常,任务执行的时间取决于CPU的性能,所以T3相对可优化性不高,那么就智能优化T1 T2 T4了
我们可以通过合理创建线程数,减少不必要线程的创建销毁以减少T1 T4,合理维持线程空转(时刻等待任务,减少任务等待时间),以便有任务立刻执行,减小T2。后面我们会在实例中看到各种运用。

线程池的主要组成

线程池主要有以下四个部分,以下摘自本文

1.线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2.工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3.任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4.任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

Android中常见的线程池

  • ThreadPoolExecutor
    构造方法
    ThreadPoolExecutor构造方法有多个,只介绍参数较多的这个构造方法:
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {...}

int corePoolSize:核心线程数,始终运行在线程池中的线程数,及时这些线程是空闲状态也不会销毁,除非指定了allowCoreThreadTimeOut参数

corePoolSize the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set

int maximumPoolSize:

maximumPoolSize the maximum number of threads to allow in the pool

线程池最大线程数
long keepAliveTime:

keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads

非核心线程空闲的超时时间,如果非核心线程任务执行完毕,空闲状态超过keepAliveTime,则会被GC。如果allowCoreThreadTimeOut被指定,该参数也指核心线程超时时间
TimeUnit unit:

unit the time unit for the {@code keepAliveTime} argument

keepAliveTime的单位,指以下几种
NANOSECONDS
MICROSECONDS
MILLISECONDS
SECONDS
MINUTES
HOURS
DAYS

BlockingQueue workQueue:

workQueue the queue to use for holding tasks before they are executed.
This queue will hold only the {@code Runnable} tasks submitted by the
{@code execute} method.

工作队列,当线程数达到maximumPoolSize时,新创建的线程会被放到workQueue中等待其他线程执行完毕
corePoolSize maximumPoolSize workQueue三者数量关系:
corePoolSize为核心线程数
maximumPoolSize为核心线程+非核心线程数
workQueue为线程等待数
任务执行的优先级是这样的:如果有空闲的核心线程,交给核心线程,否则放到workQueue中,如果workQueue已满,则看看非核心线程是否满了,未满,放入非核心线程,否则抛出异常。
也就是:当创建的线程数>(maximumPoolSize+workQueue),则线程数量超出上限,抛出异常

ThreadFactory threadFactory:

threadFactory the factory to use when the executor creates a new
thread

用来创建线程的ThreadFactory类型。ThreadFactory是一个接口,通常需要指定实现类。常见实现类有以下两个
Executors.DefaultThreadFactory
Executors.PrivilegedThreadFactory
通常只要使用默认的ThreadFactory即可,除非自定义线程池才会使用到自定义ThreadFactory。自定义ThreadFactory需要指定线程优先级,name,守护状态,ThreadGroup等参数。

RejectedExecutionHandler handler:

handler the handler to use when execution is blocked because the
thread bounds and queue capacities are reached

当线程池中的线程数量已经达到最大数,会拒绝接受task,抛出异常。

特性
参数较多,基本可以定义自己想要的线程池,下面介绍的几种线程池大多数都可以通过指定ThreadPoolExecutor的参数来实现相同的效果
例子

    public static void main(String [] args){ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3, 5,  1, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(10));for (int i = 0; i < 15; i++) {  final int INDEX = i;  Runnable runnable = new Runnable() {public void run() {  try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("CHJ"+"run: " + INDEX);}  };  poolExecutor.execute(runnable);  }  }

创建线程池,核心线程3 非核心线程2(5-3),线程队列10(最大任务数15)

大家可能对LinkedBlockingDeque比较陌生,这其实是BlockingQueue的具体实现类。
BlockingQueue常见实现类:

ArrayBlockingQueue 实现基于数组,需指定大小,线程遵循FIFO(先入先出)
LinkedBlockingQueue 实现基于链表,可以不指定大小,此时队列大小为Integer.MAX_VALUE(也可指定大小),线程遵循FIFO(先入先出)
PriorityBlockingQueue 实现基于priority heap,无大小限制(逻辑上),添加线程操作可能由于OutOfMemoryError而失败,排序方式依赖Comparable(意味着队列中的任务是实现了Comparable的)
SynchronousQueue 异步队列,可以提高程序性能,但如果需要保持同步,不要使用
  • FixedThreadPool
    构造方法
    public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}

可以看到,newFixedThreadPool指定了线程数,同时他只有核心线程。

线程的超时时间为0,说明核心线程即使在没有任务可执行的时候也不会被销毁(这样可让FixedThreadPool更快速的响应请求),最后的线程队列是一个LinkedBlockingQueue,但是LinkedBlockingQueue却没有参数,这说明线程队列的大小为Integer.MAX_VALUE(2的31次方减1),OK,看完参数,我们大概也就知道了FixedThreadPool的工作特点了,当所有的核心线程都在执行任务的时候,新的任务只能进入线程队列中进行等待,直到有线程被空闲出来。

特性
只有核心线程,且数目在初始化时就确定,workQueue不限大小。
例子

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);for (int i = 0; i < 15; i++) {  final int INDEX = i;  Runnable runnable = new Runnable() {public void run() {  try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("CHJ"+"run: " + INDEX);}  };   fixedThreadPool.execute(runnable);}

上述例子创建了一个创建了一个拥有3个核心线程,workQueue大小为Integer最大值的线程池,for循环创建了15个任务,线程池执行时先将3个task放入核心线程,其余放到workQueue,之后核心线程执行完毕后,从队列取出task继续执行。

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

可以看到,和FixedThreadPool极为类似,只不过SingleThreadExecutor只有一个核心线程
特性
只有一个核心线程
例子

public static void main(String [] args) throws InterruptedException{ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();for (int i = 0; i < 15; i++) {  final int INDEX = i;  Runnable runnable = new Runnable() {public void run() {  try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("CHJ"+"run: " + INDEX);}  };     singleThreadPool.execute(runnable);}    }

上述例子创建了一个创建了一个拥有1个核心线程,workQueue大小为Integer最大值的线程池,for循环创建了15个任务,线程池执行时先将1个task放入核心线程,其余放到workQueue,之后核心线程执行完毕后,从队列取出task继续执行,每次只能执行一个任务。

  • CachedThreadPool
    构造方法
    public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}

可以看到,CachedThreadPool没有核心线程,有Integer.MAX_VALUE个非核心线程,非核心线程60s超时,同时workQueue是SynchronousQueue,也就是支持任务异步
特性
没有核心线程,非核心线程数为Integer.MAX_VALUE,支持task异步
例子

public static void main(String [] args) throws InterruptedException{ExecutorService cachedThreadPool = Executors.newCachedThreadPool();for (int i = 0; i < 15; i++) {  final int INDEX = i;  Runnable runnable = new Runnable() {public void run() {  try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("CHJ"+"run: " + INDEX);}  };    }  cachedThreadPool.execute(runnable);}

上述例子创建了一个创建了一个拥有0个核心线程,非核心线程为Integer.MAX_VALUE,workQueue支持异步的线程池,for循环创建了15个任务,线程池执行时先将15个task放入workQueue,从队列取出task,使用非核心线程执行任务。

  • ScheduledThreadPool
    构造方法
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);}public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}    

可以看出,核心线程数可以指定,非核心线程数为Integer.MAX_VALUE,workQueue类型为DelayedWorkQueue
特性
可以指定任务完成后的等待时间
例子

    public static void main(String[] args) throws InterruptedException {ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);Runnable runnable = null;runnable = new Runnable() {public void run() {System.out.println("Task start"+ format(System.currentTimeMillis()));try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("CHJ " + "run: " + " " + format(System.currentTimeMillis()) + "thread id"+ Thread.currentThread().getName());System.out.println("Task end" + format(System.currentTimeMillis()));}};System.out.println("Task start all"+ format(System.currentTimeMillis()));// scheduledThreadPool.schedule(runnable, 1, TimeUnit.SECONDS);// scheduledThreadPool.scheduleAtFixedRate(runnable, 1, 4,// TimeUnit.SECONDS);scheduledThreadPool.scheduleWithFixedDelay(runnable, 1, 3,TimeUnit.SECONDS);}static String format(long time) {SimpleDateFormat formatter = new SimpleDateFormat("HH时mm分ss秒");Date date = new Date(time);return formatter.format(date);}
    scheduledThreadPool.schedule(runnable, 1, TimeUnit.SECONDS);延时1s启动线程scheduledThreadPool.scheduleAtFixedRate(runnable, 1, 4,TimeUnit.SECONDS);延时1s后启动线程,之后不管任务何时完成,从启动线程开始,每隔四秒尝试重新执行任务(如果任务没有执行完成,向后顺延直到任务完成)scheduledThreadPool.scheduleWithFixedDelay(runnable, 1, 3,TimeUnit.SECONDS);延时1s后启动线程,之后,任务完成后等待三秒,执行下一次任务

总结

FixedThreadPool 核心线程大小固定,线程等待队列大小为整型max,没有非核心线程
SingleThreadExecutor 与FixedThreadPool极为类似,只有一个核心线程
CachedThreadPool 没有核心线程,非核心线程数Integer.MAX_VALUE,支持task异步,线程空闲60s后自动回收
ScheduledThreadPool 可以指定任务执行频率,推迟时间等等,任务调度十分方便

Android线程池的简单使用相关推荐

  1. Android线程池详解

    引入线程池的好处 1)提升性能.创建和消耗对象费时费CPU资源 2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多. 我们来看一下线程池的简单的构造 [html] view plaincopy ...

  2. android 线程池

    为什么用线程池 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 例如: 记创建线程消耗时间T1,执行任务消耗时间T2,销毁线程消耗时间T3 如果T1+T3>T2 ...

  3. Android 线程池的使用

    线程池优点 提到线程池就必须先说一下线程池的优点,线程池的优点可以概括为以下四点: * 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销: * 线程池旨在线程的复用,就避免了创建线程和销毁 ...

  4. Android 线程池概念及使用

    一:使用线程池的原因 在android开发中经常会使用多线程异步来处理相关任务,而如果用传统的newThread来创建一个子线程进行处理,会造成一些严重的问题: 在任务众多的情况下,系统要为每一个任务 ...

  5. 线程池的简单创建和实现

    线程池的简单创建和实现:如下 转载于:https://www.cnblogs.com/cdlyy/p/11568482.html

  6. java 任务池_多线程的应用-异步任务线程池的简单实现

    对于服务端的应用而言,经常会出现比如定时任务,或者任务的异步执行,熟悉Java开发的开发者,经常会使用Executors类,其提供了4种不同的线程池: ​newCachedThreadPool, ne ...

  7. Android 线程池管理工具类

    转自Android 线程池 public class AppExecutors {private static final String TAG = "AppExecutors"; ...

  8. C/C++ 线程池的简单封装

    **C/C++ 线程池的简单封装 最近在搭建一个服务器,打算把线程池应用进去,根据老师课上所讲和网上前辈们提供的资料对线程池有了以下总结:** 一.线程的创建需要内存资源,线程的创建和销毁需要时间资源 ...

  9. Android线程池简单使用

    线程池使用的好处: 1)对多个线程进行统一地管理,避免资源竞争中出现的问题. 2)对线程进行复用,线程在执行完任务后不会立刻销毁,而会等待另外的任务,这样就不会频繁地创建.销毁线程和调用GC. 使用T ...

最新文章

  1. 最新!这所顶尖大学录取线全国第三!毕业生深造率超九成!
  2. unity 摄像头跟着鼠标移动_Unity新手入门:摄像机随玩家一起移动
  3. 企业破产重整网_送战友,踏征程……企业破产法律知识介绍二
  4. 金蝶K3很有意义的数字3
  5. tomcat 并发数已满_记一次天猫商城系统高并发的优化
  6. 域名商2014年度报告:中国数据域名总量跌至22万
  7. busybox tftp
  8. java 8 新特性之日期-时间 API
  9. 【One by One系列】IdentityServer4(四)授权码流程
  10. linux监控目录容量,利用ZABBIX监控某个目录大小
  11. java ssh 和mvc_JAVA三大框架SSH和MVC
  12. 基于SVD的推荐算法
  13. Numbers 档案如何转Excel .xlsx 格式?
  14. 【MFC】测边网平差计算
  15. 视频直播app源码,可拖拽悬浮球
  16. 你对计算机有什么看法英语作文,关于电脑优点英语作文
  17. day5 安装Linux服务器面板管理工具
  18. 为什么 Redis 单线程却能支撑高并发?
  19. ios-唯一标识符及Keychain共享
  20. HOJ 2550 百步穿杨

热门文章

  1. iviewtable表格数据 录音播放下载
  2. neo4jcypher基本语句
  3. 第二章 信息的表示和处理
  4. jquery学习之路jquery之一:jquery选择元素的方法,太神了 2012.8.2
  5. Tapestry 和 JSF
  6. PAT乙级(1035 插入与归并)
  7. python中冒号报错_python中一些常见的错误_后端开发
  8. 定积分华里士公式推广_数学分析第九章《定积分》备考指南
  9. Oracle统计信息中的Pending Statistics
  10. 语音识别端到端模型解读:FSMN及其变体模型