个人博客:

http://www.milovetingting.cn

在Android中,主线程不能执行耗时的操作,否则可能会导致ANR。那么,耗时操作应该在其它线程中执行。线程的创建和销毁都会有性能开销,创建过多的线程也会由于互相抢占系统资源而导致阻塞的现象。这个时候,就需要使用线程池。

线程池的优点可以概括为以下几点:

  • 1、重用线程池中的线程,避免线程创建、销毁带来的性能开销;

  • 2、能有效地控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源导致的阻塞现象;

  • 3、能够对线程进行简单的管理。

以上线程池的优点引用自《Android开发艺术探索》

线程池的具体实现类为ThreadPoolExecutor,ThreadPoolExecutor继承自AbstractExecutorService,AbstractExecutorService又实现了ExecutorService接口,ExecutorService继承自Executor。

ThreadPoolExecutor有四个重载的构造方法:

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
} public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
} public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
} public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> 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;
}

最终都调用到了:

/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param 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.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> 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;
}

对应这个方法中的参数:

  • corePoolSize:核心线程数。如果没有设置allowCoreThreadTimeOut为true,则核心线程空闲时也不会销毁。如果设置allowCoreThreadTimeOut为true,则受keepAliveTime控制,空闲时间超过keepAliveTime,会被回收。

  • maximumPoolSize:最大线程数。

  • keepAliveTime:非核心线程的空闲超时时长。超过这个时间,非核心线程会被回收。核心线程如果allowCoreThreadTimeOut为true,则在空闲超过这个时间也会被回收。

  • unit:超时的单位。

  • workQueue:线程池中的任务队列。通过线程池的execute()方法提交的Runnable任务会被放入任务队列中。

  • threadFactory:线程工厂。

  • handler:饱和策略。当任务队列和线程池都满后,对新提交的任务的处理策略。

ThreadPoolExecutor执行任务的规则:

  • 1、如果线程池中的线程数量未达到核心线程数量,则开启一个新的核心线程来执行任务

  • 2、如果线程池中的线程数量已经大于等于核心线程数量,则会把新的任务放入任务队列中

  • 3、如果任务队列已满,并且线程池中的线程未满,则开启非核心线程来处理新的任务

  • 4、如果任务队列和线程池都已满,则会交给handler饱和策略来处理

下面通过一个简单的案例来验证以上规则:

static class WorkThread implements Runnable {

	private String name;

	public WorkThread(String name) {
this.name = name;
} public void run() {
try {
Thread.sleep(5000);
System.out.println("Thread: " + name + " work finish");
} catch (Exception e) {
e.printStackTrace();
} }
}; Executor executor = new ThreadPoolExecutor(5, 100, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5));
for (int i = 0; i < 20; i++) {
WorkThread thread = new WorkThread("" + i);
executor.execute(thread);
}

定义了一个线程池,核心线程池数量为5,线程数量为100,超时时间为60秒,任务队列为5。在子线程中,sleep 5秒来模拟耗时的操作。然后开启了20个线程,并放入线程池中执行。执行的结果如下:

Thread: 0 work finish
Thread: 1 work finish
Thread: 13 work finish
Thread: 10 work finish
Thread: 3 work finish
Thread: 11 work finish
Thread: 4 work finish
Thread: 2 work finish
Thread: 19 work finish
Thread: 18 work finish
Thread: 17 work finish
Thread: 15 work finish
Thread: 16 work finish
Thread: 14 work finish
Thread: 12 work finish
Thread: 5 work finish
Thread: 9 work finish
Thread: 8 work finish
Thread: 7 work finish
Thread: 6 work finish

前五个线程在核心线程中执行,第6-10个线程由于核心线程已满,因此在任务队列中等待执行,第11-20个线程,由于核心线程和队列都已满,而线程池中还可以开启线程,因此在非核心线程中执行。从结果来看,线程0-4,10-19会先执行完,然后任务队列中的线程5-9才执行,验证了以上的线程池任务执行规则。

为便于使用线程池,线程池还有几种简便的定义方法:

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
} public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
} public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
} public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
} public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}

通过Executors的static方法来创建。其中:

  • FixedThreadPool:线程数量固定的线程池。从方法的定义来看,这种线程池里的线程全都是核心线程,并且没有超时时间,任务队列也是没有限制的。

  • CachedThreadPool:这种线程池没有核心线程,全是非核心线程,并且超时时间为60秒,任务队列没有限制。这种线程适合执行大量的耗时较短的任务。

  • SingleThreadExecutor:只有一个核心线程,没有超时时间,任务队列没有限制。可以确保任务按顺序执行。

  • ScheduledThreadPool:核心线程数量固定。非核心线程没有限制。非核心线程闲置时会被立即回收。这类线程池适合执行定时任务和具有固定周期的重复任务。

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

  1. android中的线程池学习笔记

    阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...

  2. android中对线程池的理解与使用

    前段时间有幸接到腾讯上海分公司的 Android开发面试,虽然最后一轮被毙了.但还是得总结一下自己在android开发中的一些盲点,最让我尴尬的是面试官问我几个android中线程池的使用与理解..哎 ...

  3. Android中的线程池概述

    线程池 Android里面,耗时的网络操作,都会开子线程,在程序里面直接开过多的线程会消耗过多的资源,在众多的开源框架中也总能看到线程池的踪影,所以线程池是必须要会把握的一个知识点; 线程运行机制 开 ...

  4. Android中的线程池 ThreadPoolExecutor

    线程池的优点: 重用线程池中的线程,避免因为线程的创建和销毁带来的性能消耗 能有效的控制线程的最大并发数,避免大量的线程之间因抢占系统资源而导致的阻塞现象 能够对线程进行简单的管理,并提供定时执行以及 ...

  5. android开发学习 ------- 【转】 android中的线程池

    线程很常见 , https://blog.csdn.net/seu_calvin/article/details/52415337    参考,保证能看懂.

  6. Android开发之线程池使用总结

    线程池算是Android开发中非常常用的一个东西了,只要涉及到线程的地方,大多数情况下都会涉及到线程池.Android开发中线程池的使用和Java中线程池的使用基本一致.那么今天我想来总结一下Andr ...

  7. Android中后台线程如何与UI线程交互

    我想关于这个话题已经有很多前辈讨论过了.今天算是一次学习总结吧. 在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须 ...

  8. java 中的线程池

    1.实现下面的一个需求,控制一个执行函数只能被五个线程访问 package www.weiyuan.test; public class Test { public static void main( ...

  9. Java5中的线程池实例讲解

    Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活.本文通过一个网络服务器模型,来实践Java5的多线程 ...

随机推荐

  1. TFS线上生成环境发布历程

    继前文 TFS在项目中Devops落地进程(上) TFS在项目中DevOps落地进程(下) 自从之前将开发环境使用TFS进行了自动化之后,就享受在此成果中,其他后续进度就停顿了好一段时间. 毕竟在我们 ...

  2. CopyOnWriteArrayList你都不知道,怎么拿offer?

    前言 只有光头才能变强 前一阵子写过一篇COW(Copy On Write)文章,结果阅读量很低啊...COW奶牛!Copy On Write机制了解一下 可能大家对这个技术比较陌生吧,但这项技术是挺 ...

  3. 使用Git过程中经常会遇到的问题

    目录 git pull如何强制覆盖本地文件 Git如何同时删除本地分支和远程分支 Git如何撤销最近一次提交 Git撤销本地的最后一次提交 Git撤销最近一次远程提交 如何修改提交信息和文件 修改本地 ...

  4. php 通过header下载中文文件名 压缩包损坏或文件不存在的问题

    开发中大家都是使用的utf8编码,昨天遇到一个奇坑,本是一件很小的问题,解决也浪费了个吧小时.废话不多说,植入正题: 文件下载方式:通过header二进制流文件下载需求: 文件上传保留文件名不变数据字 ...

  5. DDL(数据定义语言)

    1.Oracle中常见的数据类型分类:(A) 1.number(x,y) 数字类型,x表示最大长度,y表示精度对应java中除char外所有基本数据类型(byte.short.int.long.flo ...

  6. openlayers4 入门开发系列之迁徙图篇(附源码下载)

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

  7. sqlserver2012 在视图中建索引

      第一种 如果已经有视图但是要加索引只需要执行 以下SQL就好(前提是此视图必须                    绑定到架构) CREATE UNIQUE CLUSTERED INDEX in ...

  8. Linux 桌面玩家指南:01. 玩转 Linux 系统的方法论

    特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...

  9. 线性回归预测PM2.5----台大李宏毅机器学习作业1(HW1)

    一.作业说明 给定训练集train.csv,要求根据前9个小时的空气监测情况预测第10个小时的PM2.5含量. 训练集介绍: (1)CSV文件,包含台湾丰原地区240天的气象观测资料(取每个月前20天 ...

  10. 蓝牙协议中的SBC编解码原理和仿真

    一.SBC的原理 SBC是subband codec的缩写,中文叫做次频带编码,也叫子带编码.其基本原理是把信号的频率分为若干子带,然后对每个子带进行编码,并根据每个子带的重要性及特点分配不同的位数( ...