Android中的线程池

很久没有更新了,首先跟各位说声对不起。近段时间陷进了失眠的深渊难以自拔,工作、生活一团糟,每天都是满满的负能量,学习上并没有什么心得值得分享,所以也就无从下笔。几经挣扎,感觉好点了。今日见到项目中前辈封装了一个线程池的管理类,其实非常简单,寥寥数十行代码。

public class ThreadPoolManager {
private ExecutorService service;  
 private static ThreadPoolManager manager;  
 private ThreadPoolManager() {
  int num = Runtime.getRuntime().availableProcessors();       
  this.service = Executors.newFixedThreadPool(num * 2);  
 }
public static ThreadPoolManager getInstance() {
if(manager == null) {
manager = new ThreadPoolManager();      
 }
return manager;  
 }
public void addTask(Runnable runnable) {
this.service.submit(runnable);   }}

使用很简单,通过单例获得管理类的实例,调用addTask方法,传入一个Runnable对象即可进行异步的操作。
在以往的项目中,大部分的耗时操作都是网络操作,譬如接口请求,文件下载等等,这些一般都是使用第三方封装好的网络框架,遇到一些IO类的耗时操作一般都是直接通过继承Thread类或者实现Runnable接口或者AsyncTask(其实AsyncTask中也使用了线程池)去实现。虽然一直知道有个叫线程池的东西,却一直没有去使用,因为之前了解不多,不如Thread、Runnable和AsyncTask用得顺手,直到我见到这个线程池管理类,我才认真去了解了一下。总的来说,用线程池有以下3个优点:
1.重用已经创建的好的线程,避免频繁创建进而导致的频繁GC
2.控制线程并发数,合理使用系统资源,提高应用性能
3.可以有效的控制线程的执行,比如定时执行,取消执行等
Android中的线程池的概念来源于Jaca中的Executor接口,它的真正实现类为ThreadPoolExecutor。ThreadPoolExecutor中提供了一系列参数来配置线程池,通过不同的参数可以创建不同的线程池,从线程池的功能特性来说,Android的线程池主要分为四类,这四类线程池可以通过Executor所提供的工厂方法来得到。由于Android中的线程池都是直接或间接通过配置ThreadPoolExecutor来实现的,所以先介绍一下ThreadPoolExecutor。
下面这个是ThreadPoolExecutor的常用构造方法

public ThreadPoolExecutor(int corePoolSize,    
 int maximumPoolSize,   
  long keepAliveTime,   
 TimeUnit unit,    
 BlockingQueue<Runnable> workQueue,     
ThreadFactory threadFactory,    
 RejectedExecutionHandler handler)

corePoolSize 线程池中核心线程的数量
maximumPoolSize 线程池中最大线程数量
keepAliveTime 非核心线程的超时时长,当系统中非核心线程闲置时间超过keepAliveTime之后,则会被回收。如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,则该参数也表示核心线程的超时时长
unit 第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等
workQueue 线程池中的任务队列,该队列主要用来存储已经被提交但是尚未执行的任务。存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。
threadFactory 为线程池提供创建新线程的功能,这个我们一般使用默认即可
handler 拒绝策略,当线程无法执行新任务时(一般是由于线程池中的线程数量已经达到最大数或者线程池关闭导致的),默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException。
ThreadPoolExecutor遵循如下规则:1.execute一个线程之后,如果线程池中的线程数未达到核心线程数,则会立马启用一个核心线程去执行
2.execute一个线程之后,如果线程池中的线程数已经达到核心线程数,且workQueue未满,则将新线程放入workQueue中等待执行
3.execute一个线程之后,如果线程池中的线程数已经达到核心线程数但未超过非核心线程数,且workQueue已满,则开启一个非核心线程来执行任务
4.execute一个线程之后,如果线程池中的线程数已经超过非核心线程数,则拒绝执行该任务
以下是的简单使用方法

ThreadPoolExecutor mThreadPoolExecutor new ThreadPoolExecutor(3, 5,1,
 TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(128));
mThreadPoolExecutor.execute(new Runnable() {
@Override  
public void run() {
//耗时操作  
}});

下面来介绍Android中常见的四类具有不同功能特性的线程池,它们都直接或间接地通过配置ThreadPoolExecutor来实现自己的功能特性,这四类线程池分别是FixThreadPool、CachedThreadPool、ScheduleThreadPool以及SingleThreadExecutor。
1、FixThreadPool

//构造方法
public static ExecutorService newFixThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads, nThreads, 0L,TimeUnit.MILLISECONDS, 
new LinkedBlockingQueue<Runnable>());
}
//使用  
Executors.newFixThreadPool(5).execute(r);

它是一种线程数量固定的线程池,当线程处于空闲状态时并不会被回收除非线程池被关闭了。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。由于FixThreadPool只有核心线程并且这些线程不会被回收,意味着它的响应会更加迅速。
2、CachedThreadPool

public static ExecutorService newCachedThreadPool(int nThreads){
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, 
TimeUnit. SECONDS, new SynchronousQueue<Runnable>());  
}
//使用    
Executors.newCachedThreadPool().execute(r);

CachedThreadPool只有非核心线程,最大线程数非常大,所有线程都活动时,会为新任务创建新线程,否则利用空闲线程(60s空闲时间,过了就会被回收,所以线程池中有0个线程的可能)处理任务。任务队列SynchronousQueue相当于一个空集合,导致任何任务都会被立即执行。
3、** SingleThreadPool**

public static ExecutorService newSingleThreadPool (int nThreads){
return new FinalizableDelegatedExecutorService (
new ThreadPoolExecutor (1, 1, 0, TimeUnit. MILLISECONDS,
new LinkedBlockingQueue<Runnable>()) );  }
//使用   
 Executors.newSingleThreadPool ().execute(r);

****从配置参数可以看出,SingleThreadPool只有一个核心线程,确保所有任务都在同一线程中按顺序完成。因此不需要处理线程同步的问题。
4、ScheduledThreadPool

public static ScheduledExecutorServicenewScheduledThreadPool(int corePoolSize){
return new ScheduledThreadPoolExecutor(corePoolSize);   
  }
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize, Integer.MAX_VALUE, 
0,NANOSECONDS, new DelayedQueue ());     }
//使用,延迟1秒执行,每隔2秒执行一次Runnable r       
Executors. newScheduledThreadPool (5).scheduleAtFixedRate(r,
 1000, 2000, TimeUnit.MILLISECONDS);

ScheduledThreadPool核心线程数固定,非核心线程(闲着没活干会被立即回收)数没有限制,从上面代码也可以看出,ScheduledThreadPool主要用于执行定时任务以及有固定周期的重复任务。

扫码关注公号

推荐阅读更多精彩内容

  • 线程池的优点: 重用线程池中的线程,避免因为线程的创建和销毁带来的性能消耗 能有效的控制线程的最大并发数,避免大量...
    乆丩乣阅读 4,164评论 6 28
  • 线程池的优点: 1.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。 2.能有效控制线程池的最大并发...
    铜角大王阅读 12评论 0 0
  • 线程池的好处 (1)重用线程池中的线程,避免因为线程的创建和销毁所带来的性能的开销。(2)能有效控制线程池的最大并...
    蓝枫zeke阅读 59评论 0 2
  • 1.什么是线程池 我们想要使用一个线程的时候,可以创建一个线程,但如果要用多个线程,就要创建多个线程。但线程是一种...
    四会歌神陈子豪阅读 291评论 2 6
  • Android 中的四种线程池 在开发中使用线程池的优点 重用线程池中的线程,避免因为线程的创建和销毁带来的性能开...
    任教主来也阅读 45评论 0 0