引言

Android的线程池概念来自于Java的Executor,真正的线程池实现为ThreadPoolExecutor。在Android中,提供了4类不同的线程池,具体下面会说到。为什么使用线程池呢?而不是使用Thread创建线程呢?因为使用线程池有以下几个优点:

  • 重用线程池的线程,避免因为线程的创建和销毁所带来的性能开销
  • 能有效控制线程池的最大并发数,避免线程之间抢占资源导致阻塞
  • 能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能

所以需要多次创建Thread时使用线程池较好。

ThreadPoolExecutor

它是线程池的真正实现,构造函数提供一系列的参数配置线程池。

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
  • corePoolSize:核心线程数,默认情况下,即时处于闲置状态下,核心线程会在线程一直存活;如果设置allowCoreThreadTimeOut为true,闲置的核心线程等待任务期间会有超时策略,时间间隔由keepAliveTime设置,最大为CPU核心数+1
  • maximumPoolSize:线程池容纳最大线程数,当活动线程数超过这个数值,后续的新任务会导致阻塞,最大为CPU核心数2倍+1
  • keepAliveTime:非核心线程闲置时超时的时长,如果设置allowCoreThreadTimeOut为true,即作用于闲置的核心线程
  • unit:时间单位,使用TimeUnit枚举
  • workQueue:线程池中的任务队列,通过线程池execute方法提交Runnable对象会存储这个参数中,容量为128
  • threadFactory:线程工厂,为线程池提供创建新线程的功能
  • handler:线程池对拒绝任务的处理策略。一般是队列已满或者无法成功执行任务,这时ThreadPoolExecutor会调用handler的rejectedExecution方法来通知调用者,有四个策略:
    • ThreadPoolExecutor.AbortPolicy() 直接抛出异常RejectedExecutionException
    • ThreadPoolExecutor.CallerRunsPolicy() 直接调用run方法并且阻塞执行
    • ThreadPoolExecutor.DiscardPolicy() 直接丢弃后来的任务
    • ThreadPoolExecutor.DiscardOldestPolicy() 丢弃在队列中队首的任务

执行任务规则可用currentSize表示线程池中当前线程数量,将上述过程可以表示如下

  • 当currentSize < corePoolSize时,直接启动一个核心线程并执行任务
  • 当currentSize>=corePoolSize、并且workQueue未满时,添加进来的任务会被安排到workQueue中等待执行
  • 当workQueue已满,但是currentSize<maximumPoolSize时,会立即开启一个非核心线程来执行任务
  • 当currentSize>=corePoolSize、workQueue已满、并且currentSize>maximumPoolSize时,调用handler默认抛出RejectExecutionExpection异常
  • 当currentSize >corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
  • 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

FixedThreadPool

通过Executors的newFixedThreadPool方法创建,它是一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。由于FixedThreadPool只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速地响应外界的请求。

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

CachedThreadPool

通过Executors的newCachedThreadPool方法创建,它是一种线程数量不定的线程池,它只有非核心线程,并且最大线程数为Integer.MAX_VALUE,从CachedThreadPool的特性来看,这类线程池比较适合执行大量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候CachedThreadPool之中实际上是没有任何线程的,它几乎是不占用任何系统资源的。

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

ScheduledThreadPool

通过Executors的newScheduledThreadPool方法创建,它的核心线程是固定的,非核心线程数是没有限制的,主要用于执行定时任务和具有固定周期的重复任务。

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

SingleThreadExecutor

通过Executors的newSingleThreadExecutor方法创建,它只有一个核心线程,确保所有任务都在同一个线程中按顺序执行,使得这些不需要处理线程同步问题。

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

Android ThreadPoolExecutor线程池的更多相关文章

  1. 13.ThreadPoolExecutor线程池之submit方法

    jdk1.7.0_79  在上一篇<ThreadPoolExecutor线程池原理及其execute方法>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法 ...

  2. ThreadPoolExecutor 线程池的源码解析

    1.背景介绍 上一篇从整体上介绍了Executor接口,从上一篇我们知道了Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newSchedul ...

  3. j.u.c系列(01) ---初探ThreadPoolExecutor线程池

    写在前面 之前探索tomcat7启动的过程中,使用了线程池(ThreadPoolExecutor)的技术 public void createExecutor() { internalExecutor ...

  4. Java并发——ThreadPoolExecutor线程池解析及Executor创建线程常见四种方式

    前言: 在刚学Java并发的时候基本上第一个demo都会写new Thread来创建线程.但是随着学的深入之后发现基本上都是使用线程池来直接获取线程.那么为什么会有这样的情况发生呢? new Thre ...

  5. ThreadPoolExecutor 线程池

    TestThreadPoolExecutorMain package core.test.threadpool; import java.util.concurrent.ArrayBlockingQu ...

  6. 十、自定义ThreadPoolExecutor线程池

    自定义ThreadPoolExecutor线程池 自定义线程池需要遵循的规则 [1]线程池大小的设置 1.计算密集型: 顾名思义就是应用需要非常多的CPU计算资源,在多核CPU时代,我们要让每一个CP ...

  7. Executors、ThreadPoolExecutor线程池讲解

    官方+白话讲解Executors.ThreadPoolExecutor线程池使用 Executors:JDK给提供的线程工具类,静态方法构建线程池服务ExecutorService,也就是Thread ...

  8. SpringBoot项目框架下ThreadPoolExecutor线程池+Queue缓冲队列实现高并发中进行下单业务

    主要是自己在项目中(中小型项目) 有支付下单业务(只是办理VIP,没有涉及到商品库存),目前用户量还没有上来,目前没有出现问题,但是想到如果用户量变大,下单并发量变大,可能会出现一系列的问题,趁着空闲 ...

  9. 手写线程池,对照学习ThreadPoolExecutor线程池实现原理!

    作者:小傅哥 博客:https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki 沉淀.分享.成长,让自己和他人都能有 ...

随机推荐

  1. Hadoop 系列文章(二) Hadoop配置部署启动HDFS及本地模式运行MapReduce

    接着上一篇文章,继续我们 hadoop 的入门案例. 1. 修改 core-site.xml 文件 [bamboo@hadoop-senior hadoop-2.5.0]$ vim etc/hadoo ...

  2. hadoop2.4.0伪分布式搭建以及分布式关机重启后datanode没起来的解决办法

    1.准备Linux环境 1.0点击VMware快捷方式,右键打开文件所在位置 -> 双击vmnetcfg.exe -> VMnet1 host-only ->修改subnet ip ...

  3. two sum --无脑法

    public class Solution { /* * @param numbers: An array of Integer * @param target: target = numbers[i ...

  4. FTP主动模式与被动模式,及java FTPClient模式设置

    FTP的主动模式与被动模式 FTP服务器使用20和21两个网络端口与FTP客户端进行通信. FTP服务器的21端口用于传输FTP的控制命令,20端口用于传输文件数据. FTP主动模式: FTP客户端向 ...

  5. linq转载

    在说LINQ之前必须先说说几个重要的C#语言特性 一:与LINQ有关的语言特性 1.隐式类型 (1)源起 在隐式类型出现之前, 我们在声明一个变量的时候, 总是要为一个变量指定他的类型 甚至在fore ...

  6. 在Git中设置自己的姓名

    在Git中,自己的姓名与每一个commit提交绑定在一起.如果你在使用Azure DevOps Server中的Git Repo时,一定要注意commit中的提交者与服务器上的推送者,是两个概念. 在 ...

  7. 某公司的C#面试题

    1. 请简述值类型与引用类型的区别 答: 可参考http://www.cnblogs.com/JimmyZhang/archive/2008/01/31/1059383.html 2.C#中所有引用类 ...

  8. Ngon 是啥

    https://www.gamefromscratch.com/post/2011/07/11/So-whats-an-ngon-anyways.aspx 在 blender 里面 Add 一个 Cy ...

  9. Swift5 语言指南(三) 快速之旅

    传统表明,新语言中的第一个程序应在屏幕上打印“Hello,world!”字样.在Swift中,这可以在一行中完成: print("Hello, world!") // Prints ...

  10. linux下静态链接库和动态链接库

    关于链接库的知识,网上太多资料了,但是并不代表我很熟悉.今天遇到了 一个问题,就是由于静态链接库和ubuntu系统不兼容导致的,虽然花了点时间才搞定 但是,其中暴露的问题也不少. 没有区分好静态链接库 ...