前言:

上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己来自定义一个线程池,今天来学习一下ThreadPoolExecutor,然后结合使用场景定义一个按照线程优先级来执行的任务的线程池。

线程管理相关文章地址:

ThreadPoolExecutor

ThreadPoolExecutor线程池用于管理线程任务队列、若干个线程。

1.)ThreadPoolExecutor构造函数
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue workQueue,RejectedExecutionHandler handler)
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory, RejectedExecutionHandler handler)

  corePoolSize: 线程池维护线程的最少数量
  maximumPoolSize:线程池维护线程的最大数量
  keepAliveTime: 线程池维护线程所允许的空闲时间
  unit: 线程池维护线程所允许的空闲时间的单位
  workQueue: 线程池所使用的缓冲队列
  threadFactory:线程池用于创建线程
  handler: 线程池对拒绝任务的处理策略

2.)创建新线程

默认使用Executors.defaultThreadFactory(),也可以通过如下方式

    /**
* 创建线程工厂
*/
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1); @Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "download#" + mCount.getAndIncrement());
}
};
3.)线程创建规则

ThreadPoolExecutor对象初始化时,不创建任何执行线程,当有新任务进来时,才会创建执行线程。构造ThreadPoolExecutor对象时,需要配置该对象的核心线程池大小和最大线程池大小

  1. 当目前执行线程的总数小于核心线程大小时,所有新加入的任务,都在新线程中处理。
  2. 当目前执行线程的总数大于或等于核心线程时,所有新加入的任务,都放入任务缓存队列中。
  3. 当目前执行线程的总数大于或等于核心线程,并且缓存队列已满,同时此时线程总数小于线程池的最大大小,那么创建新线程,加入线程池中,协助处理新的任务。
  4. 当所有线程都在执行,线程池大小已经达到上限,并且缓存队列已满时,就rejectHandler拒绝新的任务。

4.)默认的RejectExecutionHandler拒绝执行策略

  1. AbortPolicy 直接丢弃新任务,并抛出RejectedExecutionException通知调用者,任务被丢弃
  2. CallerRunsPolicy 用调用者的线程,执行新的任务,如果任务执行是有严格次序的,请不要使用此policy
  3. DiscardPolicy 静默丢弃任务,不通知调用者,在处理网络报文时,可以使用此任务,静默丢弃没有几乎处理的报文
  4. DiscardOldestPolicy 丢弃最旧的任务,处理网络报文时,可以使用此任务,因为报文处理是有时效的,超过时效的,都必须丢弃

我们也可以写一些自己的RejectedExecutionHandler,例如拒绝时,直接将线程加入缓存队列,并阻塞调用者,或根据任务的时间戳,丢弃超过限制的任务。

5.)任务队列BlockingQueue

排队原则

  1. 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。

  2. 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。

  3. 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。

常见几种BlockingQueue实现

1. ArrayBlockingQueue :  有界的数组队列
  2. LinkedBlockingQueue : 可支持有界/无界的队列,使用链表实现
  3. PriorityBlockingQueue : 优先队列,可以针对任务排序
  4. SynchronousQueue : 队列长度为1的队列,和Array有点区别就是:client thread提交到block queue会是一个阻塞过程,直到有一个worker thread连接上来poll task。

6.)线程池执行

  execute()方法中,调用了三个私有方法
  addIfUnderCorePoolSize():在线程池大小小于核心线程池大小的情况下,扩展线程池
  addIfUnderMaximumPoolSize():在线程池大小小于线程池大小上限的情况下,扩展线程池
  ensureQueuedTaskHandled():保证在线程池关闭的情况下,新加入队列的线程也能正确处理

7.)线程池关闭

  shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
  shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

ThreadPoolExecutor实现优先级线程池

1.)定义线程优先级枚举
/**
* 线程优先级
*/
public enum Priority {
HIGH, NORMAL, LOW
}
2.)定义线程任务
/**
* 带有优先级的Runnable类型
*/
/*package*/ class PriorityRunnable implements Runnable { public final Priority priority;//任务优先级
private final Runnable runnable;//任务真正执行者
/*package*/ long SEQ;//任务唯一标示 public PriorityRunnable(Priority priority, Runnable runnable) {
this.priority = priority == null ? Priority.NORMAL : priority;
this.runnable = runnable;
} @Override
public final void run() {
this.runnable.run();
}
}
3.)定义一个PriorityExecutor继承ThreadPoolExecutor
public class PriorityExecutor extends ThreadPoolExecutor {

    private static final int CORE_POOL_SIZE = 5;//核心线程池大小
private static final int MAXIMUM_POOL_SIZE = 256;//最大线程池队列大小
private static final int KEEP_ALIVE = 1;//保持存活时间,当线程数大于corePoolSize的空闲线程能保持的最大时间。
private static final AtomicLong SEQ_SEED = new AtomicLong(0);//主要获取添加任务 /**
* 创建线程工厂
*/
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1); @Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "download#" + mCount.getAndIncrement());
}
}; /**
* 线程队列方式 先进先出
*/
private static final Comparator<Runnable> FIFO = new Comparator<Runnable>() {
@Override
public int compare(Runnable lhs, Runnable rhs) {
if (lhs instanceof PriorityRunnable && rhs instanceof PriorityRunnable) {
PriorityRunnable lpr = ((PriorityRunnable) lhs);
PriorityRunnable rpr = ((PriorityRunnable) rhs);
int result = lpr.priority.ordinal() - rpr.priority.ordinal();
return result == 0 ? (int) (lpr.SEQ - rpr.SEQ) : result;
} else {
return 0;
}
}
}; /**
* 线程队列方式 后进先出
*/
private static final Comparator<Runnable> LIFO = new Comparator<Runnable>() {
@Override
public int compare(Runnable lhs, Runnable rhs) {
if (lhs instanceof PriorityRunnable && rhs instanceof PriorityRunnable) {
PriorityRunnable lpr = ((PriorityRunnable) lhs);
PriorityRunnable rpr = ((PriorityRunnable) rhs);
int result = lpr.priority.ordinal() - rpr.priority.ordinal();
return result == 0 ? (int) (rpr.SEQ - lpr.SEQ) : result;
} else {
return 0;
}
}
}; /**
* 默认工作线程数5
*
* @param fifo 优先级相同时, 等待队列的是否优先执行先加入的任务.
*/
public PriorityExecutor(boolean fifo) {
this(CORE_POOL_SIZE, fifo);
} /**
* @param poolSize 工作线程数
* @param fifo 优先级相同时, 等待队列的是否优先执行先加入的任务.
*/
public PriorityExecutor(int poolSize, boolean fifo) {
this(poolSize, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new PriorityBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE, fifo ? FIFO : LIFO), sThreadFactory);
} public PriorityExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
} /**
* 判断当前线程池是否繁忙
* @return
*/
public boolean isBusy() {
return getActiveCount() >= getCorePoolSize();
} /**
* 提交任务
* @param runnable
*/
@Override
public void execute(Runnable runnable) {
if (runnable instanceof PriorityRunnable) {
((PriorityRunnable) runnable).SEQ = SEQ_SEED.getAndIncrement();
}
super.execute(runnable);
}
}

里面定义了两种线程队列模式: FIFO(先进先出) LIFO(后进先出) 优先级相同的按照提交先后排序

4.)测试程序
 ExecutorService executorService = new PriorityExecutor(5, false);
for (int i = 0; i < 20; i++) {
PriorityRunnable priorityRunnable = new PriorityRunnable(Priority.NORMAL, new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName()+"优先级正常");
}
});
if (i % 3 == 1) {
priorityRunnable = new PriorityRunnable(Priority.HIGH, new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName()+"优先级高");
}
});
} else if (i % 5 == 0) {
priorityRunnable = new PriorityRunnable(Priority.LOW, new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName()+"优先级低");
}
});
}
executorService.execute(priorityRunnable);
}

运行结果:不难发现优先级高基本上优先执行了 最后执行的基本上优先级比较低

Android线程管理之ThreadPoolExecutor自定义线程池的更多相关文章

  1. Android线程管理(一)——线程通信

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  2. ThreadPoolExecutor自定义线程池

    1.ThreadPoolExecutor创建线程池的构造函数 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long ...

  3. python---基础知识回顾(十)进程和线程(py2中自定义线程池和py3中的线程池使用)

    一:自定义线程池的实现 前戏: 在进行自定义线程池前,先了解下Queue队列 队列中可以存放基础数据类型,也可以存放类,对象等特殊数据类型 from queue import Queue class ...

  4. ACE线程管理机制-面向对象的线程类ACE_Task

    转载于:http://www.cnblogs.com/TianFang/archive/2006/12/05/583231.html 我们在前一章中使用ACE_Thread包装时,你一定已经注意到了一 ...

  5. Android线程管理之ExecutorService线程池

    前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...

  6. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  7. Android线程管理之Thread使用总结

    前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...

  8. Android线程管理之AsyncTask异步任务

    前言: 前面几篇文章主要学习了线程以及线程池的创建与使用,今天来学习一下AsyncTask异步任务,学习下AsyncTask到底解决了什么问题?然而它有什么弊端?正所谓知己知彼百战百胜嘛! 线程管理相 ...

  9. 基于ThreadPoolExecutor,自定义线程池简单实现

    一.线程池作用 在上一篇随笔中有提到多线程具有同一时刻处理多个任务的特点,即并行工作,因此多线程的用途非常广泛,特别在性能优化上显得尤为重要.然而,多线程处理消耗的时间包括创建线程时间T1.工作时间T ...

随机推荐

  1. python开发编译器

    引言 最近刚刚用python写完了一个解析protobuf文件的简单编译器,深感ply实现词法分析和语法分析的简洁方便.乘着余热未过,头脑清醒,记下一点总结和心得,方便各位pythoner参考使用. ...

  2. 加深一下BlockingQueue的认识

    认识BlockingQueue BlockingQueue是一种可以阻塞线程的队列,java中对这种队列提供了方法抽象,BlockingQueue则是抽象的接口. add:添加元素到队列里,添加成功返 ...

  3. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  4. 2D、3D形变

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px Monaco; color: #a5b2b9 } span.Apple-tab-span { ...

  5. Web APi之认证(Authentication)两种实现方式【二】(十三)

    前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...

  6. 在Linux系统下运行微信Web开发者工具

    微信Web开发者工具只有window版本和mac版本,如果想要在Linux系统下运行微信Web开发者工具,需要花费很大周折. 注:带 * 的步骤或文件为不确定是否管用的步骤或文件.本人系统为Linux ...

  7. JVM类加载

    JVM的类加载机制就是:JVM把描述类的class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型 ClassLoader JVM中的ClassLoade ...

  8. A/B Testing的简要知识

    A/B testing主要用来检测网站或者APP的两个版本中哪一个更好,它的中心思想是把流量一分为二,一份用作experiment group,访问新的版本,另一份用作control group,访问 ...

  9. 两个变量交换的四种方法(Java)

    对于两种变量的交换,我发现四种方法,下面我用Java来演示一下. 1.利用第三个变量交换数值,简单的方法. (代码演示一下) class TestEV //创建一个类 { public static ...

  10. x01.os.23: 制作 linux LiveCD

    1.首先运行如下命令  sudo apt-get install wget bc build-essential gawk genisoimage 2.下载如下资源,make all 即可 http: ...