写在前面
之前参加过的一些面试中,或多或少有问到类似如下的问题:
- android中如何创建线程?
- android有哪些执行耗时任务的方法?
- android中有哪些异步的方式?
以上的这些问题,实质上其实都是关于线程和线程池的问题,当然还要回答一些比如Async Task和Intent Service的东西。但是当问到第一点时,千万别以为面试官只是单纯地想听你说“继承于Thread来写自己的子类”“用new Thread(Runnable)来构造新的线程再启动”,面试官真正期待的回答一定是想让你也讲讲线程池的用法的。
Thread缺点
每次线程的构造和启动,以及最后执行完的回收都需要消耗宝贵的CPU资源,如果不加以合理的控制,比如要大量显示网络的图片,从而产生大量的thread来下载网络图片时,这样的效率是极其低下的。
所以如果只知道在遇到异步任务的时候上来就用Thread,那只能说offer会与你失之交臂了。
Async Task缺点
参考链接:http://blog.youkuaiyun.com/goodlixueyong/article/details/45895997
主要是4个方面,生命周期、内存泄漏、结果丢失、版本不同。值得注意的是Async Task实现是基于线程池的。
线程池的优点
在前面的种种情形下,终于可以开始讲线程池的优势:
- 重用线程池中的线程,避免了创建、销毁线程时带来的开销。
- 能有效控制线程池的最大并发数,避免大量线程之间抢占资源导致的拥塞。
- 能提供一些简单的管理,比如定时执行等。
Android提供的4种线程池均基于ThreadPoolExecutor,构造方法中有如下的参数:
- int corePoolSize 核心线程的数量
- int maximumPoolSize 最大线程数量
- long keepAliveTime 非核心线程的闲置超时时长
- TimeUnit unit 上述时长的时间单位
- BlockingQueue<Runnable> workQueue 任务队列
- ThreadFactory threadFactory 线程工厂,只需要提供一个
Thread newThread(Runnable r)
方法即可。
线程池任务分配原则:
- 如果线程数少于核心线程,则创建核心线程来执行。
- 如果线程数已经大于或等于核心线程,小于最大线程数量时,优先放到队列里。
- 队列满的时候,创建新的非核心线程。
- 非核心线程达到上限,则拒绝接受。调用
RejectedExecutionHandler
的rejectionExecution
方法。
Android中的4种线程池
FixedThreadPool
核心线程数和最大线程数相同且固定,即没有非核心线程,所有多余任务处在排队队列中等待。
CachedThreadPool
线程数量不定且可认为无穷大,只有非核心线程,即所有任务都被分配在新的非核心线程或可重用的非核心线程。没有任务队列。
ScheduledThreadPool
特点是用于执行定时任务,其他特点不太好记,不详述了。
SingleThreadExecutor
特点是只有一个核心线程,保证所有任务按顺序执行,不需要处理线程同步的问题。
补充
除了AsyncTask,Thread,ThreadPool,或者是Handler.post,View.post一个异步Runnable任务,还有一种也是基于Thread的方式,比较方便执行轻量级的周期任务Timer&TimerTask。
但是Timer&TimerTask也有自己不好的地方,当timer.cancel()之后,你想再次恢复所有的任务时就之只能重新new Timer,new TimerTask了,对连TimerTask都要重新创建。。