线程池使用FutureTask的时候如果拒绝策略设置为了DiscardPolicy和DiscardOldestPolicy
并且在被拒绝的任务的Future对象上调用无参get方法那么调用线程会一直被阻塞。

阿里巴巴手册
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险
因为:
该任务队列是LinkedBlockingQueue,是无界队列,如果任务数量特别多,可能会导致内存不足
是无界队列


线程池的四种池
1、FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

2、CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM


自定义线程池的重要参数含义

1.corePoolSize 指定了线程池里的线程数量
2.maximumPoolSize 指定了线程池里的最大线程数量
3.keepAliveTime 当线程池线程数量大于corePoolSize时候,多出来的空闲线程,多长时间会被销毁。
4.unit 时间单位
5.workQueue 任务队列,用于存放提交但是尚未被执行的任务。
6.threadFactory 线程工厂,用于创建线程,一般可以用默认的
7.handler 拒绝策略,当任务过多时候,如何拒绝任务。

corePoolSize and maximumPoolSize 解释意义流程图

image.png
corePoolSize:核心线程数;maximunPoolSize:最大线程数
每当有新的任务到线程池时,
第一步: 先判断线程池中当前线程数量是否达到了corePoolSize,若未达到,则新建线程运行此任务,且任务结束后将该线程保留在线程池中,不做销毁处理,若当前线程数量已达到corePoolSize,则进入下一步;
第二步: 判断工作队列(workQueue)是否已满,未满则将新的任务提交到工作队列中,满了则进入下一步;
第三步: 判断线程池中的线程数量是否达到了maxumunPoolSize,如果未达到,则新建一个工作线程来执行这个任务,如果达到了则使用饱和策略来处理这个任务。
[

](https://blog.csdn.net/qq_33323054/article/details/106923732)


keepAliveTime

如果一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。
举个例子,如果线程池的核心大小corePoolSize=5,而当前大小poolSize =8,那么超出核心大小的线程,会按照keepAliveTime的值判断是否会超时退出。
如果线程池的核心大小corePoolSize=5,而当前大小poolSize =5,那么线程池中所有线程都是核心线程,这个时候线程是否会退出,取决于allowCoreThreadTimeOut。

队列workQueue

缓冲队列有三种通用策略:直接提交、有界队列、无界队列
SynchronousQueue、ArrayBlockingQueue、LinkedBlockingQueue、

SynchronousQueue:
由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加
image.png

ArrayBlockingQueue:
有界队列,特点可以防止资源耗尽, 默认有界长度 2147483647(二十一亿 四千七百四十八万多)

LinkedBlockingQueue:
无界队列,会造成资源耗尽

handler 拒绝策略JDK 提供了四种内置拒绝策略,我们要理解并记住,有如下的四种:

  1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  2. ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 极大概率是main线程去执行

https://www.jianshu.com/p/aa420c7df275

ThreadFactory来定义我们自己的线程工厂,比如说自定义线程名称,组,优先级等信息,可以跟着线程池究竟在何时创建了多少线程等等。


使用Executors 创建线程池

newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

  1. public static void main(String[] args) {
  2. Date time = Calendar.getInstance().getTime();
  3. // Single();
  4. //Scheduled(time);
  5. System.out.println(time);//开始时间
  6. //可缓存的线程池 核心线程数无限大,所以即使线程输出完成 休眠十秒,十个线程也是在一瞬间执行完成的
  7. ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  8. for (int i = 0; i < 10; i++) {
  9. final int index = i;
  10. cachedThreadPool.execute(() -> {
  11. System.out.println(Thread.currentThread().getName()+":"+index);
  12. System.out.println(Calendar.getInstance().getTime());
  13. try {
  14. Thread.sleep(10000);//休眠十秒
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. });
  19. }
  20. }


newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

  1. public static void main(String[] args) {
  2. Date time = Calendar.getInstance().getTime();
  3. // Single();
  4. //Scheduled(time);
  5. //CaChed(time);
  6. ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
  7. for (int i = 0; i < 10; i++) {
  8. fixedThreadPool.execute(() -> {
  9. try {
  10. System.out.println(Calendar.getInstance().getTime() + ";当前线程名称" + Thread.currentThread().getName());
  11. Thread.sleep(3000);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. });
  16. }
  17. /*
  18. Sat Apr 13 11:03:37 CST 2019;当前线程名称pool-1-thread-3
  19. Sat Apr 13 11:03:37 CST 2019;当前线程名称pool-1-thread-2
  20. Sat Apr 13 11:03:37 CST 2019;当前线程名称pool-1-thread-1
  21. Sat Apr 13 11:03:40 CST 2019;当前线程名称pool-1-thread-3
  22. Sat Apr 13 11:03:40 CST 2019;当前线程名称pool-1-thread-2
  23. Sat Apr 13 11:03:40 CST 2019;当前线程名称pool-1-thread-1
  24. Sat Apr 13 11:03:43 CST 2019;当前线程名称pool-1-thread-3
  25. Sat Apr 13 11:03:43 CST 2019;当前线程名称pool-1-thread-2
  26. Sat Apr 13 11:03:43 CST 2019;当前线程名称pool-1-thread-1
  27. Sat Apr 13 11:03:46 CST 2019;当前线程名称pool-1-thread-3
  28. */
  29. }

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

  1. public static void main(String[] args) {
  2. // Single();
  3. Date time = Calendar.getInstance().getTime();
  4. System.out.println(time);
  5. //核心线程数量 2
  6. ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
  7. for (int i = 0; i < 5; i++) {
  8. scheduledThreadPool.schedule(() -> {
  9. System.out.println("三秒后执行,每次间隔两秒" + Calendar.getInstance().getTime() + ";当前线程名称" + Thread.currentThread().getName());
  10. try {
  11. Thread.sleep(2000);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. }, 3, TimeUnit.SECONDS);
  16. }
  17. /*
  18. Sat Apr 13 10:28:51 CST 2019
  19. 三秒后执行,每次间隔两秒Sat Apr 13 10:28:54 CST 2019;当前线程名称pool-1-thread-1
  20. 三秒后执行,每次间隔两秒Sat Apr 13 10:28:54 CST 2019;当前线程名称pool-1-thread-2
  21. 三秒后执行,每次间隔两秒Sat Apr 13 10:28:56 CST 2019;当前线程名称pool-1-thread-1
  22. 三秒后执行,每次间隔两秒Sat Apr 13 10:28:56 CST 2019;当前线程名称pool-1-thread-2
  23. 三秒后执行,每次间隔两秒Sat Apr 13 10:28:58 CST 2019;当前线程名称pool-1-thread-2
  24. */
  25. }

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

  1. public static void main(String[] args) {
  2. //单例的线程
  3. ExecutorService service = Executors.newSingleThreadExecutor();
  4. for (int i = 0; i < 5 ; i++) {
  5. service.execute(() -> {
  6. System.out.println(Thread.currentThread().getName()+ " : " + "查看线程是否是单例的");
  7. try {
  8. Thread.sleep(2000);
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. });
  13. }
  14. }
  15. --------------------------------------
  16. pool-1-thread-1 : 查看线程是否是单例的
  17. pool-1-thread-1 : 查看线程是否是单例的
  18. pool-1-thread-1 : 查看线程是否是单例的
  19. pool-1-thread-1 : 查看线程是否是单例的
  20. pool-1-thread-1 : 查看线程是否是单例的
  1. private final BlockingQueue<Runnable> workQueue; // 阻塞队列
  2. private final ReentrantLock mainLock = new ReentrantLock(); // 互斥锁
  3. private final HashSet<Worker> workers = new HashSet<Worker>();// 线程集合.一个Worker对应一个线程
  4. private final Condition termination = mainLock.newCondition();// 终止条件
  5. private int largestPoolSize; // 线程池中线程数量曾经达到过的最大值。
  6. private long completedTaskCount; // 已完成任务数量
  7. private volatile ThreadFactory threadFactory; // ThreadFactory对象,用于创建线程。
  8. private volatile RejectedExecutionHandler handler;// 拒绝策略的处理句柄
  9. private volatile long keepAliveTime; // 线程池维护线程所允许的空闲时间
  10. private volatile boolean allowCoreThreadTimeOut;
  11. private volatile int corePoolSize; // 线程池维护线程的最小数量,哪怕是空闲的
  12. private volatile int maximumPoolSize; // 线程池维护的最大线程数量