1.1. 为什么要用线程池?

这里借用《Java 并发编程的艺术》提到的来说一下使用线程池的好处:

  • 降低资源消耗==》通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度==》当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  • 提高线程的可管理性==》线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

1.2. Java线程池有哪些?

线程池有4 种:
1、newFixedThreadPool:创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中;

2、newSingleThreadPool:创建一个单线程的线程池,如果线程异常结束会创建一个新的线程,可以保证任务是按照队列中的顺序穿行执行;

3、newCacheThreadPool:创建一个可以缓存的线程池,当需求线程个数 < 线程池个数,就回收一部分线程;反之超过线程池的数量,就会添加新的线程,线程池的规模不受限制;

4、newScheduledThreadPool:创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行

1、newFixedThreadPool 和 newSingleThreadPool 采用的是无界 LinkedBlockingQueue 队列实现,其中队列有入队和出队方法putLock 和 takeLock ,可以同时实现入队和出队,因为链表的原因,查找速度慢===链表阻塞队列

2、newCacheThreadPool 使用的是SyncronousQueue队列

3、newScheduledThreadPool 使用的是DelayedWorkQueue()队列

1.3.怎么创建线程池

《阿里巴巴 Java 开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险

Executors 返回线程池对象的弊端如下:

FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE ,可能堆积大量的请求,从而导致 OOM。
CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。

创建线程池方式一:通过构造方法实现

创建线程池方式二:通过 Executor 框架的工具类 Executors 来实现

我们可以创建三种类型的 ThreadPoolExecutor:

  • FixedThreadPool : 该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。

  • SingleThreadExecutor: 方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。

  • CachedThreadPool: 该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用