线程池


线程池

有关线程池的创建、常见的几种线程池,线程池的使用方式

创建线程池

创建线程池:

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

各个参数含义

参数 含义
corePoolSize 核心线程数
maximumPoolSize 最大线程数
keepAliveTime和unit 空闲存活时间
workQueue 任务缓存队列
threadFactory 线程工厂
handler 拒绝策略

线程池的执行流程为、

  1. 线程池中的线程未达到核心线程,提交任务后就会立刻执行任务
  2. 线程池中的线程达到核心线程数,将任务提交到任务缓存队列
  3. 任务缓存队列已满,未达到最大线程数,将会创建新的线程执行任务
  4. 达到最大线程数,执行拒绝策略

线程池执行流程

  • 拒绝策略类型
初始化 特性
ThreadPoolExecutor.AbortPolicy() 抛出异常
ThreadPoolExecutor.DiscardPolicy() 直接丢弃不抛出异常
ThreadPoolExecutor.DiscardOldestPolicy() 丢弃队列中存在最长的时间
ThreadPoolExecutor.CallerRunsPolicy() 由提交任务的线程来执行任务

ThreadPoolExecutor.CallerRunsPolicy() 这种拒绝策略比较合理,通过将任务由提交任务的线程去执行这样可以减少任务的累积

Executers.new

初始化 特性
Executors.newCachedThreadPool() 无上限的线程数的线程池,线程会保持60s
Executors.newFixedThreadPool() 固定线程数,无上限的缓存任务队列
Executors.newSingleThreadExecutor() 单个线程,无上限的缓存任务队列
Executors.ScheduledThreadPoolExecutor() 有固定线程数,延迟队列

ForkJoinPool

ForkJoinPool线程池

ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask task = forkJoinPool.submit(new Fibonacci(i));
task.get();

阻塞队列

初始化 特性
LinkedBlockingQueue 无容量上限的队列
SynchronousQueue 无容量的队列,提交任务立即弹出
DelayedWorkQueue 延迟队列

核心线程数的选择

核心线程数的选择是根据任务的类型CPU密集性IO密集型

CPU密集性任务,会一直使用cpu进行计算,合适的线程数为cpu核心数的1~2倍,过多的线程数会造成线程上下文的频繁切换,执行效率反而不高。

IO密集型任务,会执行IO任务,cpu进行等待,因此线程数可以尽量多一些。

*线程数 = CPU核心数 (1 + 平均等待时间/平均工作时间)

shutdown和shutdownNew的区别

shutdown不在允许提交任务,待执行线程池中正在执行的任务和任务队列中的任务后线程池关闭
shutdownNow立即暂停任务,向正在执行任务的线程发送中断信号,将等待队列中的任务转移出来,然后线程池关闭

线程池复用线程的逻辑是,创建线程后不停的获取task进行执行(run)方法


  TOC