【前言】咱们从事Android开发以来,都自始自终被灌输着处理耗时的任务时要在非UI线程作。因而咱们有了各类处理并发的编程手段,不管是本身用new Thread(Runnable)新起工做线程(Worker thread),仍是利用Android提供的API(AsnyTask,CursorLaoder等)都是处理耗时任务的解决方案。可是在一个大型的应用程序中,若是咱们须要处理数量不少且频繁的耗时任务时,若是仍是采用以前的手段,无疑会带来不少不便;一来频繁建立销毁线程会形成资源(内存和Cpu)的浪费,二来代码会显得很凌乱。因而咱们提出了使用线程池来处理频繁的耗时任务。java
在JDK1.5的类库中,JAVA的开发者就给咱们提供了现成的线程池,java.util.concurrent包下就提供了线程池的api。编程
个人应用架构设计中,在处理并发的任务时,就要用到线程池,关于线程池,我把它想成是一个统一管理多线程任务的地方,具体来讲,就是线程池接受多线程任务(实现Runnable接口),并经过建立线程池时配置好的一些参数来统一管理和执行这些任务,咱们在须要执行耗时任务的时候,只须要向线程池发送一个消息(但愿执行的耗时操做)就能够了,固然,咱们在发送请求的同时,能够传入一些回调的接口,这样就能在耗时任务执行完毕以后获得回调来更新UI。api
如何实现自定义的线程池?多线程
JDK提供的线程池当然能够知足通常的开发需求,可是实现自定义的线程池仍是颇有必要的。架构
自定义线程池通常能够继承自类ThreadPoolExcutor,该类的构造方法里面有几个很重要的参数,这几个参数决定着线程池的策略和处理能力。并发
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)线程
corePoolSize - 池中所保存的线程数,包括空闲线程。架构设计
maximumPoolSize - 池中容许的最大线程数。设计
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。继承
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
threadFactory - 执行程序建立新线程时使用的工厂。
handler - 因为超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
这些参数既能够在构造的时候传入,也能够在后期经过set方法来设定。
setMaximumPoolSize(int maximumPoolSize)
setRejectedExecutionHandler(RejectedExecutionHandler handler)
setKeepAliveTime(long time, TimeUnit unit)
setCorePoolSize(int corePoolSize)
线程池表达了一种边界的概念,这个边界是经过corePoolSize和maximumPoolSize来体现的,若是线程池接受的任务小于corePoolSize,则新提交的任务会被线程池经过新建线程来处理,若是大于corePoolSize而小于maximumPoolSize,则新传入的任务会被排队队列容纳,若是队伍容纳不下或者队列是直接提交型队列时,任务就会被提交给线程池,线程池会建立新线程来处理任务,若是大于maximumPoolSize,则新加入的任务会被拒绝,这里要注意的时,被拒绝的意思并不等于被抛弃,只是会触发线程池的RejectExecutionHandler,这里咱们能够经过设置自定义的handler来实现线程池的拒绝策略(好比用一个队列来保存被拒绝的任务,之后还能够从该队列取出任务继续执行)。
在自定义线程池的时候,选择合适的排队队列显得尤其重要,咱们通常有如下三种队列可选
SynchronousQueue 直接提交队列,该队列不会保存任务,而是会把任务直接提交给线程池。
LinkedBlockingQueue 无界队列,这队列没有极限,能够无限加入任务保存,这样maximumPoolSize就不起做用了,建立的线程数就永远不会超过corePoolSize了。
ArrayBlockingQueue 有界队列。
如何处理被拒绝任务?
1.定义被拒绝的策略
当 Executor 已经关闭,而且 Executor 将有限边界用于最大线程和工做队列容量,且已经饱和时,在方法 execute(java.lang.Runnable) 中提交的新任务将被拒绝。在以上两种状况下,execute 方法都将调用其RejectedExecutionHandler 的RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor) 方法。
ThreadPoolExecutor.AbortPolicy
用于被拒绝任务的处理程序,它将抛出 RejectedExecutionException.
ThreadPoolExecutor.DiscardOldestPolicy
用于被拒绝任务的处理程序,它放弃最旧的未处理请求,而后重试 execute;若是执行程序已关闭,则会丢弃该任务。
ThreadPoolExecutor.DiscardPolicy
用于被拒绝任务的处理程序,默认状况下它将放弃被拒绝的任务。
2.自定义RejectedExecutionHandler
使用自定义RejectedExecutionHandler来定义线程池的拒绝策略,好比用一个队列来保存被拒绝的任务以便之后继续执行或者直接丢弃。
更多灵活的处理
ThreadPoolExcutor提供了一些可被覆写的hook方法
afterExecute(Runnable r,Throwable t)
基于完成执行给定 Runnable 所调用的方法。
beforeExecute(Thread t,Runnable r)
在执行给定线程中的给定 Runnable 以前调用的方法。
这两个方法在每一个任务被线程池执行先后都被会回调,因此咱们能够覆写这两个方法来自定义须要的功能。