阅读书籍: 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. First Blog

    俗话说“笨鸟先飞”,遗憾的是我这只笨鸟直到今天才意识到个人博客的重要性. 原来记录下学习生活中的每一丝领悟与思考,可以让个人内在,对知识的理解得到更好的升华. 有梦的人很美,追梦的人更美.像我的座右铭 ...

  2. hibernate笔记--单向一对多映射方法

    上一篇讲的是单向多对一的表关系,与单向一对多的关系正好相反,如下图所示关系: ,可以看出年级表和学生表是一对多的关系,一条年级信息对应多条学生信息,在hibernate中成为单向的一对多的映射关系,应 ...

  3. C#创建安全的字典(Dictionary)存储结构

    在上面介绍过栈(Stack)的存储结构,接下来介绍另一种存储结构字典(Dictionary). 字典(Dictionary)里面的每一个元素都是一个键值对(由二个元素组成:键和值) 键必须是唯一的,而 ...

  4. ThinkPHP学习(一)

    下载3.2框架后,解压缩到web目录下面,可以看到初始的目录结构如下: 3.2版本相比之前的版本自带了一个完整的应用目录结构和默认的应用入口文件,开发人员可以在这个基 础之上灵活调整.其中, Appl ...

  5. TCP滑动窗口机制

    我们可以大概看一下上图的模型: 首先是AB之间三次握手建立TCP连接.在报文的交互过程中,A将自己的缓冲区大小(窗口大小)3发送给B,B同理,这样双方就知道了对端的窗口大小. A开始发送数据,A连续发 ...

  6. Linux中读写权限

    learn the auth of Linux.   Generally, r-x w: write , modify and delete  -2 r: read   -4 x: execute   ...

  7. jQuery-1.9.1源码分析系列(十五) 动画处理——缓动动画核心Tween

    在jQuery内部函数Animation中调用到了createTweens()来创建缓动动画组,创建完成后的结果为: 可以看到上面的缓动动画组有四个原子动画组成.每一个原子动画的信息都包含在里面了. ...

  8. [Tool] csdn客户端开发(非官方版)

    偶尔间看到一篇博客[清山博客]里讲述了他自己开发的一个CSDN博客客户端,并去下载体验了一下,然后就自己手痒也要开发一下 先看看结果图: 在文章列表里,鼠标右键可以操作[置顶.删除.评论权限]: 下面 ...

  9. .Net(c#)汉字和Unicode编码互相转换

    {"Tilte": "\u535a\u5ba2\u56ed", "Href": "http://www.cnblogs.com&q ...

  10. C#~异步编程续~.net4.5主推的await&async应用

    返回目录 之前写过两篇关于异步编程的文章,详细可以进入C#~异步编程和C#~异步编程在项目中的使用 .net的各个版本都有自己主推的技术,像.NET1.1中的委托,.NET2.0中的泛型,.NET3. ...