Java 并发之线程池学习

建立

经过ThreadPoolExecutor来建立一个线程池java

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

参数说明:git

  • corePoolSize 线程池中任务的基本个数
    • 新提交一个任务时,若线程池中个数未达到基本个数,则新建一个线程
    • 到线程池中的线程数达到基本个数时,再提交任务,则看是否有空闲线程,有则只直接使用
    • 若无空闲线程,则新几条的任务放入排队
  • maximumPoolSize 线程chi池中任务的作多个数
    • 当线程池中个数达到 corePoolSize & 且队列排满了
    • 新建立线程来执行任务
    • 当线程池中任务达到maximumPoolSize,则再也不建立
  • keepAliveTime 线程池的工做线程空闲后存活的时间
  • milliseconds 配合上个参数使用,表示时间的单位,如TimeUnit.SECONDS
  • runnableTaskQueue 排队队列
    • ArrayBlockingQueue基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序
    • LinkedBlockingQueue 基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量一般要高于ArrayBlockingQueue
    • SynchronousQueue 一个不存储元素的阻塞队列。每一个插入操做必须等到另外一个线程调用移除操做,不然插入操做一直处于阻塞状态,吞吐量一般要高于LinkedBlockingQueue
    • PriorityBlockingQueue 一个具备优先级得无限阻塞队列
  • threadFactory 建立线程的工厂,一般会从新指定线程名,方便debug
  • handler 线程池饱和策略
    • 当线程数达到 maximumPoolsize 队列已满时,表示饱和
    • CallerRunsPolicy 只用调用者所在线程来运行任务
    • DiscardOldestPolicy 丢弃队列里最近的一个任务,并执行当前任务
    • DiscardPolicy 不处理,丢弃掉
    • AbortPolicy 抛异常
    • 也能够根据应用场景须要来实现RejectedExecutionHandler接口自定义策略

线程池提交任务的处理流程数据库

线程池提交任务的处理流程

提交任务

1. execute(Runnable)

直接执行一个实现了Runnable的接口,即表示提交了一个异步任务给线程池数组

2. submit(Runnable)

相比较于上面的,区别是这个会返回一个 Future<V> 对象,经过调用future.get() 能够获取线程的返回值,其中这个方程是线程阻塞的,直到返回告终果以后,才会继续执行下去微信

关闭线程

线程池的shutdown或shutdownNow方法来关闭线程池框架

shutdown的原理是只是将线程池的状态设置成SHUTDOWN状态,而后中断全部没有正在执行任务的线程异步

shutdownNow的原理是遍历线程池中的工做线程,而后逐个调用线程的interrupt方法来中断线程,因此没法响应中断的任务可能永远没法终止ui

调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当全部的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。.net

至于咱们应该调用哪种方法来关闭线程池,应该由提交到线程池的任务特性决定,一般调用shutdown来关闭线程池,若是任务不必定要执行完,则能够调用shutdownNow线程

线程池的配置

分析

  1. 任务的性质:CPU密集型任务,IO密集型任务和混合型任务。
    • CPU密集型任务配置尽量少的线程数量,如配置Ncpu+1个线程的线程池
    • IO密集型任务则因为须要等待IO操做,线程并非一直在执行任务,则配置尽量多的线程,如2*Ncpu
    • 混合型的任务,若是能够拆分,则将其拆分红一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,若是这两个任务执行时间相差太大,则不必进行分解
  2. 任务的优先级:高,中和低。
    • 优先级不一样的任务可使用优先级队列PriorityBlockingQueue来处理
  3. 任务的执行时间:长,中和短。
    • 执行时间不一样的任务能够交给不一样规模的线程池来处理,或者也可使用优先级队列,让执行时间短的任务先执行
  4. 任务的依赖性:是否依赖其余系统资源,如数据库链接。
    • 由于线程提交SQL后须要等待数据库返回结果,若是等待的时间越长CPU空闲时间就越长,那么线程数应该设置越大,这样才能更好的利用CPU

获取线程数

Runtime.getRuntime().availableProcessors()

实例分析

背景:

实现一个异步的报警case,首先是有三种报警方式,邮件、微信、短信;其次是具体的报警都是异步处理(一个报警执行的线程池);要求一分钟内报警有上限设置(即要实现报警的计数与清零);报警的重要性根据邮件-》微信-》短信进行递增,当超过每一个报警类型的最低阀值时,晋升报警类型

silver-alarm 一个报警的基本框架

源码传送门

相关文章
相关标签/搜索