0.前言并发
转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52415337性能
使用线程池能够给咱们带来不少好处,首先经过线程池中线程的重用,减小建立和销毁线程的性能开销。其次,能控制线程池中的并发数,不然会由于大量的线程争夺CPU资源形成阻塞。最后,线程池可以对线程进行管理,好比使用ScheduledThreadPool来设置延迟N秒后执行任务,而且每隔M秒循环执行一次。spa
下面会经过介绍线程池中的真正实现者——ThreadPoolExecutor来引出Android中的4类线程池的使用以及特性分析,会加上笔者本身的理解,和自认为比较恰当的比喻,帮助理解。.net
1.凡事得靠ThreadPoolExecutor(铺垫环节,懂的直接跳过)线程
Executor做为一个接口,它的具体实现就是ThreadPoolExecutor。code
Android中的线程池都是直接或间接经过配置ThreadPoolExecutor来实现不一样特性的线程池。对象
先介绍ThreadPoolExecutor的一个经常使用的构造方法。blog
1 /* 2 *@ ThreadPoolExecutor构造参数介绍 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public ThreadPoolExecutor( 7 //核心线程数,除非allowCoreThreadTimeOut被设置为true,不然它闲着也不会死 8 int corePoolSize, 9 //最大线程数,活动线程数量超过它,后续任务就会排队 10 int maximumPoolSize, 11 //超时时长,做用于非核心线程(allowCoreThreadTimeOut被设置为true时也会同时做用于核心线程),闲置超时便被回收 12 long keepAliveTime, 13 //枚举类型,设置keepAliveTime的单位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等 14 TimeUnit unit, 15 //缓冲任务队列,线程池的execute方法会将Runnable对象存储起来 16 BlockingQueue<Runnable> workQueue, 17 //线程工厂接口,只有一个new Thread(Runnable r)方法,可为线程池建立新线程 18 ThreadFactory threadFactory)
ThreadPoolExecutor的各个参数所表明的特性注释中已经写的很清楚了,那么ThreadPoolExecutor执行任务时的心路历程是什么样的呢?(如下用currentSize表示线程池中当前线程数量)接口
(1)当currentSize<corePoolSize时,没什么好说的,直接启动一个核心线程并执行任务。队列
(2)当currentSize>=corePoolSize、而且workQueue未满时,添加进来的任务会被安排到workQueue中等待执行。
(3)当workQueue已满,可是currentSize<maximumPoolSize时,会当即开启一个非核心线程来执行任务。
(4)当currentSize>=corePoolSize、workQueue已满、而且currentSize>maximumPoolSize时,调用handler默认抛出RejectExecutionExpection异常。
2. Android中的四类线程池
Android中最多见的四类具备不一样特性的线程池分别为FixThreadPool、CachedThreadPool、ScheduleThreadPool以及SingleThreadExecutor。
2.1 FixThreadPool(一堆人排队上公厕)
1 /* 2 *@FixThreadPool介绍 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ExecutorService newFixThreadPool(int nThreads){ 7 return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); 8 } 9 //使用 10 Executors.newFixThreadPool(5).execute(r);
(1)从配置参数来看,FixThreadPool只有核心线程,而且数量固定的,也不会被回收,全部线程都活动时,由于队列没有限制大小,新任务会等待执行。
(2)【前方高能,笔者脑洞】FixThreadPool其实就像一堆人排队上公厕同样,能够无数多人排队,可是厕所位置就那么多,并且没人上时,厕所也不会被拆迁,哈哈o(∩_∩)o ,很形象吧。
(3)因为线程不会回收,FixThreadPool会更快地响应外界请求,这也很容易理解,就好像有人忽然想上厕所,公厕不是现用现建的。
2.2 SingleThreadPool(公厕里只有一个坑位)
1 /* 2 *@SingleThreadPool介绍 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ExecutorService newSingleThreadPool (int nThreads){ 7 return new FinalizableDelegatedExecutorService ( new ThreadPoolExecutor (1, 1, 0, TimeUnit. MILLISECONDS, new LinkedBlockingQueue<Runnable>()) ); 8 } 9 //使用 10 Executors.newSingleThreadPool ().execute(r);
(1)从配置参数能够看出,SingleThreadPool只有一个核心线程,确保全部任务都在同一线程中按顺序完成。所以不须要处理线程同步的问题。
(2)【前方高能,笔者脑洞】能够把SingleThreadPool简单的理解为FixThreadPool的参数被手动设置为1的状况,即Executors.newFixThreadPool(1).execute(r)。因此SingleThreadPool能够理解为公厕里只有一个坑位,先来先上。为何只有一个坑位呢,由于这个公厕是收费的,收费的大爷上年纪了,只能管理一个坑位,多了就管不过来了(线程同步问题)。
2.3 CachedThreadPool(一堆人去一家很大的咖啡馆喝咖啡)
1 /* 2 *@CachedThreadPool介绍 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ExecutorService newCachedThreadPool(int nThreads){ 7 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit. SECONDS, new SynchronousQueue<Runnable>()); 8 } 9 //使用 10 Executors.newCachedThreadPool().execute(r);
(1)CachedThreadPool只有非核心线程,最大线程数很是大,全部线程都活动时,会为新任务建立新线程,不然利用空闲线程(60s空闲时间,过了就会被回收,因此线程池中有0个线程的可能)处理任务。
(2)任务队列SynchronousQueue至关于一个空集合,致使任何任务都会被当即执行。
(3)【前方高能,笔者脑洞】CachedThreadPool就像是一堆人去一个很大的咖啡馆喝咖啡,里面服务员也不少,随时去,随时均可以喝到咖啡。可是为了响应国家的“光盘行动”,一我的喝剩下的咖啡会被保留60秒,供新来的客人使用,哈哈哈哈哈,好恶心啊。若是你运气好,没有剩下的咖啡,你会获得一杯新咖啡。可是之前客人剩下的咖啡超过60秒,就变质了,会被服务员回收掉。
(4)比较适合执行大量的耗时较少的任务。喝咖啡人挺多的,喝的时间也不长。
2.4 ScheduledThreadPool(4个里面惟一一个有延迟执行和周期重复执行的线程池)
1 /* 2 *@ScheduledThreadPool介绍 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){ 7 return new ScheduledThreadPoolExecutor(corePoolSize); 8 } 9 public ScheduledThreadPoolExecutor(int corePoolSize){ 10 super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedQueue ()); 11 } 12 //使用,延迟1秒执行,每隔2秒执行一次Runnable r 13 Executors. newScheduledThreadPool (5).scheduleAtFixedRate(r, 1000, 2000, TimeUnit.MILLISECONDS);
(1)核心线程数固定,非核心线程(闲着没活干会被当即回收)数没有限制。
(2)从上面代码也能够看出,ScheduledThreadPool主要用于执行定时任务以及有固定周期的重复任务。
至此Android中最多见的四类不一样特性的线程池内容总结完毕。
转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52415337