其实在我眼里,线程池是一个很高端的东西,它会管理很多线程,并在进程中进行多线程的操作,是一个很高效且方便使用的东西。本篇文章就说说我对线程池的认识。
一,线程池的基本概念
线程池有很多优点,比如避免了重复创建和销毁线程而降低了程序的运行效率,其次它可以很方便的控制线程的最大并发数,在一定程度上可以减少线程间的阻塞等。在android中线程池是由java的Executor实现的。它的真正实现类是ThreadPoolExecutor,下面是它的构造方法和相关介绍。
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnalbe>workQueue,ThreadFactory threadFactory)
corePoolSize:核心线程数量,它会一直存在,没任务就处理闲置状态 。如果allowCoreThreadTimeOut设置为true,则闲置的核心线程会有超时策略,时间由keepAliveTime控制,当超时时,核心线程就会被终止。
maximumPoolSize:线程池能容纳的最大线程数,当活动数达到这个数时,后续的新任务将会被阻塞。
keepAliveTime:超时时非核心线程会被回收,如果allowCoreThreadTimeOut设置为true,核心线程也会被回收。
unit:指定keepAliveTime的单位。TimeUnit.MILLISECONDS(毫秒),TimeUnit.SECONDS(秒)等。
workQueue:线程中的任务队列,通过线程池的excute方法提交的Runnable会存储到这参数中。
threadFactory:线程工厂,为线程池提供创建新线程的功能。
了解了上面的概念后,我们来看下android线程池的分类。
二,线程池的分类
1.FixedThreadPool
这是一种线程数量固定的线程池。处理空闲状态时,并不会被回收,除非线程池关闭。它的源码如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
由上面介绍的ThreadPoolExecutor可知,
FixedThreadPool的核心线程有nThreads条,最大线程也相同,这证明了它没有非核心线程,且FixedThreadPool没有超时策略,所以空闲时线程不会被回收。此外它的任务队列也是无限大的。它适合用于需要快速响应的外界请求的情况下。接下来看下它的用法。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
fixedThreadPool.execute(Runnable);
用法很简单,只需要使用Executors就可创建FixedThreadPool,并初始化线程数。看到这个,以后开线程就不需要再用Thread了。
2.CacheThreadPool
是一种线程数量不定的线程池,只有非核心线程,并且最大线程数可以说是无穷大。当线程池中的线程都处于活动状态时,创建新线程。这类线程适合执行大量耗时较少的任务。看下它的构造方法:
<pre name="code" class="java"><pre name="code" class="java"> public static final int MAX_VALUE = 0x7FFFFFFF;
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
同样很好理解,没有核心线程,最大线程娄是MAX_VALUE,基本可以理解成无上限,超时机制是60秒,由上分析可知,它在闲置60秒后会被回收,所以基本不占系统资源。看下它的用法。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(runnable);
3.scheduledThreadPool
核心线程数量是固定的,而非核心线程数是没有限制的,并且非核心线程闲置时会被立即回收,可用于执行定时和具有固定周期的重复任务。看下它的构造方法:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
super就相当于调用了
ThreadPoolExecutor,看下它的用法:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
// 1s后执行command
scheduledThreadPool.schedule(runnable, 1000, TimeUnit.MILLISECONDS);
// 延迟10ms后,每隔1000ms执行一次command
scheduledThreadPool.scheduleAtFixedRate(runnable, 10, 1000, TimeUnit.MILLISECONDS);
4.SingleThreadExecutor
内部只有一个线程,确保任务都在一个线程中按顺序执行。这个多用于串行处理情况。不用考虑并发的问题。它的构造方法如下:
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
没什么好解释的,来看下它的用法:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(runnable);</span>
分析完所有线程池后,我们得知,不同线程池有不同的应用环境,并没有说哪个比较好。在实际情况中我们要根据自己的需求来适当的选择。其实线程池在android的源码中有大量的使用,下一篇博客将讲解下AsyncTask的源码解析,里面就运用了线程池。