阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家

对线程池原理的简单理解:

创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理使得多线程的使用更简单,高效.

使用线程池的优势:

1.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销.

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

3.能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能.

ThreadPoolExecutor

Android中的线程池都是直接或者间接通过配置ThreadPoolExecutor来实现的,通过不同的参数可以创建不同的线程池.

ThreadPoolExecutor类中有四个构造方法,下面是比较常用的一个.

    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)

corePoolSize

线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使他们处于闲置状态.可以通过设置ThreadPoolExecutor的allowCoreThreadTimeOut属性为true,这样闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由keepAliveTime所指定.

maximumPoolSize

线程池所能容纳的最大线程数,当活动线程数达到这个数值后,后续的新任务将会被阻塞.

keepAliveTime

非核心线程闲置时的超时时长,闲置超过这个时长,非核心线程就会被回收.当ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true时,keepAliveTime同样会作用于核心线程.

unit

用于指定keepAliveTime参数的时间单位,这是一个枚举,例如TimeUnit.MILLISECONDS等.

workQueue

线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数中.

threadFactory

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

除了以上这些参数外,还有一个不常用的参数RejectedExecutionHandler handler.当线程池无法执行新任务时(这可能是由于任务队列已满或者是无法成功执行任务),会调用handler的rejectedExecution方法来通知调用者,默认情况下该方法会直接抛出一个RejectedExecutionException.(该参数不常用)

ThreadPoolExecutor执行任务时,大致遵循如下规则:

(1)如果线程池中的线程数量未达到核心线程数,那么会直接启动一个核心线程来执行任务.

(2)如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会被插到任务队列中排队等待执行.

(3)如果在步骤2中无法将任务插入到任务队列中(这往往是由于任务队列已满),这个时候如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务.

(4)如果步骤3中线程数量已经达到线程池规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecutionHandler的RejectedExecution方法来通知调用者.

线程池的分类

从线程池的功能特性上来说,Android的线程池主要分为四类,这4类线程池可以通过Executors所提供的工厂方法来得到.

FixedThreadPool

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

特点:

从参数中可以看到FixedThreadPool中只有核心线程并且这些核心线程没有超时机制,任务队列也是没有大小限制的.

FixedThreadPool线程数量固定,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了.当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来.

由于只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速地响应外界的请求.

使用场景:

对于Android平台,由于资源有限,最常使用的就是通过Executors.newFixedThreadPool(int size)来启动固定数量的线程池

    protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); fixedThreadPool(3); } private static void fixedThreadPool(int size) {
ExecutorService executorService = Executors.newFixedThreadPool(size);
for (int i = 0;i < MAX; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
Log.i("MainActivity","执行线程: " + Thread.currentThread().getName());
}
});
}
}

执行结果:

03-31 16:03:01.016 25903-25934/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-1
03-31 16:03:01.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-2
03-31 16:03:01.016 25903-25936/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-3
03-31 16:03:03.016 25903-25934/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-1
03-31 16:03:03.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-2
03-31 16:03:03.016 25903-25936/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-3
03-31 16:03:05.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-2
03-31 16:03:05.016 25903-25934/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-1
03-31 16:03:05.016 25903-25936/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-3
03-31 16:03:07.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-2

从结果中可以看到,每隔2s有三个线程同时运行,而且是相同的三个线程.

CachedThreadPool

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

特点

从参数中可以看出,它是一种线程数量不定的线程池,而且没有核心线程,只有非核心线程,并且最大线程数为Integer.MAX_VALUE(由于Integer.MAX_VALUE是一个很大的数(0x7FFFFFFF),实际上就相当于最大线程数可以任意大).有60s超时机制,当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候几乎不占用任何系统资源.

使用场景

从CachedThreadPool的特性来看,这类线程池比较适合执行大量的耗时较少的任务.(以空间换时间)

    //省略onCreate函数

    private static void cachedThreadPool()  {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0;i < MAX; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
Log.i("MainActivity","执行线程: " + Thread.currentThread().getName());
}
});
}
}

执行结果:

03-31 16:48:47.776 6757-6791/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-7
03-31 16:48:47.776 6757-6785/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-1
03-31 16:48:47.776 6757-6787/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-3
03-31 16:48:47.776 6757-6788/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-4
03-31 16:48:47.776 6757-6789/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-5
03-31 16:48:47.776 6757-6790/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-6
03-31 16:48:47.776 6757-6786/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-2
03-31 16:48:47.776 6757-6792/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-8
03-31 16:48:47.776 6757-6793/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-9
03-31 16:48:47.776 6757-6794/com.example.janiszhang.threadpooldemo I/MainActivity: 执行线程: pool-1-thread-10

从结果来看,每次调用execute,(在没有空闲线程可用情况下)就会立即启动一个线程,所有任务几乎在同时完成.

ScheduledThreadPool

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

特点及使用场景:

从参数列表可以看出,它的核心线程数是固定的,非核心线程数没有限制.

这类线程池主要用于执行定时任务和具有固定周期的重复任务.

  protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);
//2000ms后执行command
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
Log.i("MainActivity", "执行线程: " + Thread.currentThread().getName());
}
},2000, TimeUnit.MILLISECONDS); //延迟10ms后,每隔1000ms执行一次command
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
Log.i("MainActivity", "执行线程: " + Thread.currentThread().getName());
}
},10,1000,TimeUnit.MILLISECONDS); }

SingleThreadExecutor

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

特点与使用场景:

这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行.SingleThreadExecutor的意义在于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题.

线程池的最佳大小

线程池的最佳大小取决于可用处理器的数目以及工作队列中的任务性质.

若在一个具有N个处理器的系统上只有一个工作队列,其中全部是计算性质的任务,在线程池具有N或N+1个线程时一般会获得最大的CPU利用率.

对于那些可能需要等待I/O完成的任务,需要线程池的大小超过可用处理器的数目,因为并不是所有线程都一直在工作.

android中的线程池学习笔记的更多相关文章

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

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

  2. Android中的线程池

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

  3. c++11 线程池学习笔记 (一) 任务队列

    学习内容来自一下地址 http://www.cnblogs.com/qicosmos/p/4772486.html github https://github.com/qicosmos/cosmos ...

  4. Android中的线程池概述

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

  5. Android中的线程池 ThreadPoolExecutor

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

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

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

  7. c++11 线程池学习笔记 (二) 线程池

    学习内容来自以下地址 http://www.cnblogs.com/qicosmos/p/4772486.html github https://github.com/qicosmos/cosmos ...

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

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

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

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

随机推荐

  1. C# 在excel表格中检索并导出数据

    由于工作需要,我经常使用excel文档来存储和处理各种数据,在生活中偶尔也会使用excel表格来记录各种开销,相信很多朋友也和我一样.Excel的功能很强大,其中一个很实用的数据处理功能就是查找和替换 ...

  2. 【Java】 环境变量如何配置?

    Java知识简介与环境变量配置问题 一.在学习一门语言中,不仅需要掌握其语法结构,开发平台以及环境也是很重要的.在开始Java学习之前首先对其进行压缩包的下载安装,以及开发平台环境下载安装.基于此下面 ...

  3. 相克军_Oracle体系_随堂笔记002-基础

    1.常见的Oracle生产库环境: 图2-1可以说是标准的生产库环境,处处体现了冗余,有效防止了单点故障.这就是HA(高可用) 而且冗在某种条件下还可以去掉,平常实现同时运行提供服务,如果一台坏掉,另 ...

  4. 【字符编码】Java字符编码详细解答及问题探讨

    一.前言 继上一篇写完字节编码内容后,现在分析在Java中各字符编码的问题,并且由这个问题,也引出了一个更有意思的问题,笔者也还没有找到这个问题的答案.也希望各位园友指点指点. 二.Java字符编码 ...

  5. 开源网站.NETMVC+ Layui+SqlSugar+RestSharp

    SugarSite一个前端支持移动端的企业网站,目前只支持了简单功能,后续还会加上论坛等. 源码GIT地址: https://github.com/sunkaixuan/SugarSite 技术介绍 ...

  6. Vuforia unity开发摄像头问题

    Vuforia unity开发摄像头问题 项目一直在赶进度,写博的时间越来越少了~从事Unity开发也快两个月了,AR方向~ 使用的是高通家的SDK Vuforia...从工程融合一直到对unity和 ...

  7. commons-lang包中我们常用的类的作用

    commons-lang包中对我们有用的类主要有: 1.StringUtils 该类主要提供对字符串的操作,对null是安全的,主要提供了字符串查找,替换,分割,去空白,去掉非法字符等等操作 2.Ob ...

  8. 利用Swashbuckle生成Web API Help Pages

    利用Swashbuckle生成Web API Help Pages 这系列文章是参考了.NET Core文档和源码,可能有人要问,直接看官方的英文文档不就可以了吗,为什么还要写这些文章呢? 原因如下: ...

  9. Effective java笔记(十),序列化

    将一个对象编码成字节流称作将该对象「序列化」.相反,从字节流编码中重新构建对象被称作「反序列化」.一旦对象被「序列化」后,它的编码就可以从一台虚拟机传递到另一台虚拟机,或被存储到磁盘上,供以后「反序列 ...

  10. SignalR入门之Hub

    在持久性连接的基础上,SignalR提供了一个更高层次的抽象层:Hub,基于javascript的灵活性和C#的动态特性,Hub是一个至关重要的开发模式,它消弭了客户端和服务端这两个独立的物理环境之间 ...