个人博客:

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. 使用Git过程中经常会遇到的问题

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

  2. 前端笔记之HTML

    前端三层:内容层(结构层)HTML.样式层(表现层)CSS.行为层JavaScript 层 语言 含义 结构层 HTML 由 HTML 或 XHTML之类的标记语言负责创建.标签,也就是那些出现在尖括 ...

  3. 同事搭一个测试RAC说节点2发现idle了,报ORA-00304

    [oracle@testrac2 11204]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Wed Jan 16 1 ...

  4. Doskey命令详解

    转自:https://blog.csdn.net/u012993732/article/details/48626921 调用 Doskey.exe,它撤回 Windows XP 命令.编辑命令行并创 ...

  5. python进程、进程池(二)代码部分

    第一种创建进程的方式: from multiprocessing import Process def f(name): print(name,"在子进程") if __name_ ...

  6. 数字信号处理专题(3)——FFT运算初探

    一.前言 FFT运算是目前最常用的信号频谱分析算法.在本科学习数字信号处理这门课时一直在想:学这些东西有啥用?公式推来推去的,有实用价值么?到了研究生后期才知道,广义上的数字信号处理无处不在:手机等各 ...

  7. 初始scrapy,简单项目创建和CSS选择器,xpath选择器(1)

    一 安装 #Linux: pip3 install scrapy #Windows: a. pip3 install wheel b. 下载twisted http://www.lfd.uci.edu ...

  8. gulp源码解析(一)—— Stream详解

    作为前端,我们常常会和 Stream 有着频繁的接触.比如使用 gulp 对项目进行构建的时候,我们会使用 gulp.src 接口将匹配到的文件转为 stream(流)的形式,再通过 .pipe() ...

  9. 【从零开始搭建自己的.NET Core Api框架】(七)授权认证进阶篇

    系列目录 一.  创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...

  10. python接口自动化(九)--python中字典和json的区别(详解)

    简介 这篇文章的由来是由于上一篇发送post请求的接口时候,参数传字典(dict)和json的缘故,因为python中,json和dict非常类似,都是key-value的形式,为啥还要这么传参,在群 ...