android中的线程池学习笔记
阅读书籍: 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中的线程池学习笔记的更多相关文章
- android中对线程池的理解与使用
前段时间有幸接到腾讯上海分公司的 Android开发面试,虽然最后一轮被毙了.但还是得总结一下自己在android开发中的一些盲点,最让我尴尬的是面试官问我几个android中线程池的使用与理解..哎 ...
- Android中的线程池
在Android中,主线程不能执行耗时的操作,否则可能会导致ANR.那么,耗时操作应该在其它线程中执行.线程的创建和销毁都会有性能开销,创建过多的线程也会由于互相抢占系统资源而导致阻塞的现象.这个时候 ...
- c++11 线程池学习笔记 (一) 任务队列
学习内容来自一下地址 http://www.cnblogs.com/qicosmos/p/4772486.html github https://github.com/qicosmos/cosmos ...
- Android中的线程池概述
线程池 Android里面,耗时的网络操作,都会开子线程,在程序里面直接开过多的线程会消耗过多的资源,在众多的开源框架中也总能看到线程池的踪影,所以线程池是必须要会把握的一个知识点; 线程运行机制 开 ...
- Android中的线程池 ThreadPoolExecutor
线程池的优点: 重用线程池中的线程,避免因为线程的创建和销毁带来的性能消耗 能有效的控制线程的最大并发数,避免大量的线程之间因抢占系统资源而导致的阻塞现象 能够对线程进行简单的管理,并提供定时执行以及 ...
- android开发学习 ------- 【转】 android中的线程池
线程很常见 , https://blog.csdn.net/seu_calvin/article/details/52415337 参考,保证能看懂.
- c++11 线程池学习笔记 (二) 线程池
学习内容来自以下地址 http://www.cnblogs.com/qicosmos/p/4772486.html github https://github.com/qicosmos/cosmos ...
- Android开发之线程池使用总结
线程池算是Android开发中非常常用的一个东西了,只要涉及到线程的地方,大多数情况下都会涉及到线程池.Android开发中线程池的使用和Java中线程池的使用基本一致.那么今天我想来总结一下Andr ...
- Android中后台线程如何与UI线程交互
我想关于这个话题已经有很多前辈讨论过了.今天算是一次学习总结吧. 在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须 ...
随机推荐
- typeof知多少
昨天同事给我看了一道代码题,是关于typeof的,感觉挺有意思的,在这里分享给大家,顺便自己再对typeof总结总结.如有不对,请给予指出,共同进步. 代码是这样的: <!DOCTYPE htm ...
- CSS三种写法的优先级
在HTML文件中引入CSS样式有三种方法: 外部样式:通过link标签引入CSS样式: 内页样式:写在HTML页面里面的style标签里面: 行内样式:写在对应标签的style属性里面. 我知道一般情 ...
- EntityFramework 如何进行异步化(关键词:async·await·SaveChangesAsync·ToListAsync)
应用程序为什么要异步化?关于这个原因就不多说了,至于现有项目中代码异步化改进,可以参考:实际案例:在现有代码中通过async/await实现并行 这篇博文内容针对的是,EntityFramework ...
- 网络通信简单实例BIO,NIO,AIO
这里,我将做一个简单的通信程序,分别使用三种原始的通信工具:BIO,NIO,AIO. 功能就是一个服务器,一个客户端.服务器就是处理请求,返回响应.而客户端就是连接服务器,发送请求,接收响应. 第一步 ...
- SPRING多个占位符配置文件解析源码研究--转
原文地址:http://www.cnphp6.com/archives/85639 Spring配置文件: <context:property-placeholder location=&quo ...
- IOS 整体架构 和 MVC布局
IOS的生态系统 IOS生态系统不仅仅是指产品,更重要的是指 iPhone/iPad/iPod/Mac +iCloud+App整个系统,包括Siri (部分设备不支持).FaceTime.Safari ...
- Oracle软件安装目录满的清理方法
这是Oracle数据库日常运维中很常见的一个场景,安装目录满有时不光会导致无法记录最新数据库的日志信息,导致遇到问题无法查到最新的日志信息,还会引发一些奇怪的问题. 所以日常巡检要保证Oracle的安 ...
- MonoGame 3.2 下,截屏与 Texture2D 的保存
10月20日注:后来发现了这篇博文(英文),XNA 中的 Color 实际上是与 Alpha 值自左乘(premultiplied)的,这也解释了直接用 0xARGB 转译而颜色异常的原因. 注意,由 ...
- URL的组成格式
最近在学习js的Ajax方面的内容,发现自己对基础的计算机网络知识认识不足,所以大概了解了下. URL组成格式 图中中括号是可选项 protocol 协议,常用的协议是http hostname 主机 ...
- 1.什么是Code First(EF Code First 系列)
EF4.1中开始支持Code First .这种方式在领域设计模式中非常有用.使用Code First模式,你可以专注于领域设计,根据需要,为你一个领域的对象创建类集合,而不是首先来设计数据库,然后来 ...