一、线程池定义和使用
jdk 1.5 之后就引入了线程池。
1.1 定义从上面的空间切换看得出来,线程是稀缺资源,它的创建与销毁是一个相对偏重且耗资源的操作,而Java线程依赖于内核线程,创建线程需要进行操作系统状态切换。为避免资源过度消耗需要设法重用线程执行多个任务。线程池就是一个线程缓存,负责对线程进行统一分配、调优与监控。(数据库连接池也是一样的道理)
什么时候使用线程池?
单个任务处理时间比较短;需要处理的任务数量很大。
线程池优势?
重用存在的线程,减少线程创建、消亡的开销,提高性能、提高响应速度。
当任务到达时,任务可以不需要等到线程创建就能立即执行。
提高线程的可管理性,可统一分配,调优和监控。
1.2 线程池在 jdk 已有的实现在 juc 包下,有一个接口:Executor :
Executor 又有两个子接口:ExecutorService 和 ScheduledExecutorService,常用的接口是 ExecutorService。
同时常用的线程池的工具类叫 Executors。
例如:
ExecutorService service = Executors.newCachedThreadPool();Executor 框架虽然提供了如 newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()、newScheduledThreadPool() 等创建线程池的方法,但都有其局限性,不够灵活。
上面的几种方式点进去会发现,都是用 ThreadPoolExecutor 进行创建的:
newSingleThreadExecutor 字面意思简单线程执行器。
2. newFixedThreadPool 字面意思**固定的线程池**,传参就是线程固定数目,适用于执行长期任务的场景。 3. newCachedThreadPool 字面意思**缓存线程池**,核心线程0,最大线程非常大,动态创建的特点。 4. newScheduledThreadPool 字面意思**时间安排线程池**,指定核心线程数。 5. newSingleThreadScheduledExecutor 字面意思**单线程安排执行器**,也就是基于只有一个核心线程的执行器之外,又可以扩展。其中又用 DelegatedExecutorService 委托执行器服务进行了包装。 可以看到,上面直接用 Executors 工具类默认的一些实现 new 出来的线程池都是用的 ThreadPoolExecutor 线程执行器这个类进行构造的,不过参数不同,导致了效果的侧重点不同。因此,自己创建线程池推荐的方法就是,直接使用 ThreadPoolExecutor 进行个性化的创建:
构造方法种的参数有 7 个:
corePoolSize:线程池维护线程的最少数量 (core : 核心)
maximumPoolSize:线程池维护线程的最大数量,显然必须>=1
keepAliveTime:线程池维护的多余的线程所允许的空闲时间,最长可以空闲多久,时间到了,如果超过 corePoolSize 的线程一直空闲,他们就会被销毁。
unit:线程池维护线程所允许的空闲时间的单位
workQueue:线程池所使用的缓冲队列,已经提交但是没有执行的任务会放进这里
threadFactory:生成线程池种工作线程的线程工厂,一般使用默认
handler:线程池对拒绝任务的处理策略,当队列满且工作线程已经达到maximumPoolSize。
阿里的 java 开发手册,强制要求,通过 ThreadPoolExecutor 来自定义,不能使用内置的,避免资源耗尽。这个很好理解,1 的类型就只有一个核心线程和最大现场,2 没有扩展性,3、4、5的最大线程数太大,内存会爆炸。
1.3 线程池使用方法