关于线程池的创建方式,可以是通过Executors创建,也可以是通过直接new ThreadPoolExecutor(...)来创建。但是阿里巴巴规约中要求使用第2种方式。

image.png

于是乎,我们就要先了解一下线程池的运行规则啦!!

线程池的运行规则

image.png
如上图所示,线程池包含的信息有:核心线程、阻塞队列、临时线程、拒绝策略。
上图的线程池用代码来表达的话就是:

  1. new ThreadPoolExecutor(3,// 核心线程
  2. 5,// 总线程
  3. 1,// 可空闲时间
  4. TimeUnit.SECONDS,
  5. new ArrayBlockingQueue<>(5), //阻塞队列
  6. Executors.defaultThreadFactory(), //线程工厂
  7. new ThreadPoolExecutor.AbortPolicy()); //拒绝策略

流程描述:

  1. 任务进入线程池,线程池创建线程
  2. 当3个核心线程创建并正在使用时,再次进来的线程被丢入阻塞队列
  3. 如果阻塞队列被塞满后,仍然有线程进入,则创建临时线程,但是在不超过最大线程数5的情况下
  4. 如果无法创建临时线程,则线程池使用设置的拒绝策略执行处理

线程执行完任务后,空闲keepAliveTime时间后,且池内线程数大于核心线程数时,自动销毁。

线程池的拒绝策略

我们可以看到线程池的最后一个参数是用来指定拒绝策略的。那么具体有哪几种拒绝策略呢?

AbortPolicy

直接抛出异常,如果try-catch的话,仍然可以运行。
image.png

CallerRunsPolicy

会在调用线程池的线程中执行任务,比如会在main线程中执行
image.png

DiscardPolicy

直接抛弃啥都不做,新来的线程直接扔掉

DiscardOldestPolicy

丢掉最早进入队列中的任务。注意是最早进入队列中的任务

自定义线程工厂

线程池创建线程是通过指定的线程工厂创建的。其创建的线程名称是自动生成的。但是在阿里规约中,不推荐这么做。

image.png

太棒了,同时给出了如何自定义线程工厂的例子。

  1. public class MyThreadFactory implements ThreadFactory {
  2. private final String namePrefix;
  3. private final AtomicInteger nextId = new AtomicInteger(1);
  4. public MyThreadFactory(String namePrefix) {
  5. this.namePrefix = namePrefix;
  6. }
  7. @Override
  8. public Thread newThread(Runnable r) {
  9. String nowThreadName = namePrefix + "-" + nextId.getAndIncrement();
  10. Thread thread = new Thread(null, r, nowThreadName);
  11. return thread;
  12. }
  13. }

image.png