1.使用Executors执行器创建线程池

  • newFixedThreadPool:固定个数线程池
  • 特点:核心线程数等于最大线程数;空闲时间为0;使用链表阻塞队列(无界队列)LinkedBlockingQueue
  • newSingleThreadExecutor:可执行线程数为1
  • 特点:核心线程数等于最大线程数=1;空闲时间为0;使用链表阻塞队列(无界队列)LinkedBlockingQueue
  • newCachedThreadPool:缓冲线程池
  • 特点:核心线程数为0;最大线程数为Integer.MAX_VALUE;空闲时间为60s;阻塞队列为SynchronousQueue
  • newScheduledThreadPool:定时线程池
  • 特点:指定核心线程数;最大线程数为Integer.MAX_VALUE;空闲时间为0;阻塞队列为DelayedWorkQueue
  • newWorkStealingPool:分而治之线程池
  • 特点:底层使用的是ForkJoinPool线程池;相当于对ForkJoinPool的封装,可以更好的调用;每一个线程对应一个阻塞队列
  • 总结:为什么高并发任务不推荐使用Executors提供的默认线程池?
  • newFixedThreadPool和newSingleThreadExecutor使用的是无界队列,任务量过多时,队列占用内存过大,容易oom
  • newCachedThreadPool和newScheduledThreadPool的最大线程数为Integer.MAX_VALUE,任务过多时可能生成过多的线程,导致oom,同时线程数过多可能导致CPU频繁上下文切换,影响CPU性能

2.线程池中线程执行流程简易说明

线程池中的线程执行任务的任务不是我们通过excuse或者submit提交的任务,而是在threadpollservice里面定义了一个内部类Worker,该内部类实现了runnable接口;线程真正执行的任务就是该内部类run方法,然后再该内部类的run方法里面循环队列执行提交的任务;当满足线程过期时间之后回跳出循环从而导致线程run方法执行完毕,线程回收。

3.线程池任务执行流程

  • 当前线程池线程数小于核心线程数,则创建线程执行任务。
  • 当前线程池线程数大于核心线程数,判断阻塞队列是否已满,未满则将任务放入阻塞队列。
  • 阻塞队列已满,则判断当前线程池线程数是否小于最大线程数,小于则创建线程执行任务。
  • 当前线程池线程数等于最大线程数,并且阻塞队列已满,则执行拒绝策略。

4.线程池常见拒绝策略

  • AbortPolicy:丢弃任务,抛出异常
  • CallerRunsPolicy:调用者执行任务,主线程执行
  • DiscardPolicy:丢弃任务,不抛出异常
  • DiscardOldestPolicy:丢弃队列里最老的任务,新任务进入队列
  • 实现RejectedExecutionHandler 接口自定义拒绝策略

5.自定义线程池时,7个常用参数

  • corePoolSize:核心线程数
  • maximumPoolSize:线程池最大线程数
  • keepAliveTime:线程闲置超时时间,超过该时间的限制线程会被回收,核心线程除外
  • unit:线程闲置超时时间单位
  • workQueue:任务队列
  • threadFactory:线程工厂,用于创建线程
  • rejectedExecutionHandler:拒绝策略