一. 为什么使用线程池?
借用《Java并发编程的艺术》提到的来说一下使用线程池的好处:
(1)降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
(2)提高响应速度。 当任务到达时,任务可以不需要的等到线程创建就能立即执行。
(3)提高线程的可管理性。 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
二. 如何创建线程池?
方式一:通过 ThreadPoolExecutor 的构造方法实现, 是最原始的创建线程池的方式,它包含了 7 个参数(上节讲到)可供设置。
方式二:通过工具类Executors创建的线程池。
Executors提供四种线程池:
1.newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
2.newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程按先入先出的顺序执行队列中的任务。
3.newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
4.newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
阿里巴巴《Java开发手册》强制要求线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的人更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool和ScheduledThreadPool :允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。