线程池
线程池是线程的管理机制,它主要解决两方面问题:复用线程;控制线程数量
线程池的使用场景
java中经常需要用到多线程来处理一些业务,单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池,来管理线程任务。
java中涉及到线程池的相关类均在jdk1.5开始的java.util.concurrent包中,在并发编程中很常用的实用工具类。
线程池的创建及核心参数
Executors创建线程池
Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,比如Executors.newFixedThreadPool(int nThreads),但是便捷不仅隐藏了复杂性,也为我们埋下了潜在的隐患(OOM,线程耗尽)。
Executors创建线程池常用方法
- newFixedThreadPool()方法
功能:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
参数:(nThreads - 池中的线程数)或者(int nThreads- 池中的线程数,ThreadFactory threadFactory- 创建新线程时使用的工厂)
返回:新创建的线程池
注意:当线程数量小于等于0时会抛出IllegalArgumentException(传递了一个不合法或不正确的参数异常);如果 threadFactory 为 null,则抛出NullPointerException异常 - newSingleThreadExecutor()方法
功能:创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
参数:可以不传参,也可以传入threadFactory - 创建新线程时使用的工厂
返回:新创建的单线程 Executor
注意: 如果 threadFactory 为 null,会抛出NullPointerException异常 - newCachedThreadPool()方法
功能:创建一个不限线程数上限的线程池,任何提交的任务都将立即执行
参数:可以不传参,也可传入threadFactory - 创建新线程时使用的工厂
返回:新创建的线程池
注意:如果 threadFactory 为 null,会抛出NullPointerException异常。 - 使用 ThreadPoolExecutor 构造方法,创建具有类似属性但细节不同(例如超时参数)的线程池。
ThreadPoolExecutor中参数详解:
corePoolSize:核心线程数,也是线程池中常驻的线程数,线程池初始化时默认是没有线程的,当任务来临时才开始创建线程去执行任务
maximumPoolSize:最大线程数,在核心线程数的基础上可能会额外增加一些非核心线程,需要注意的是只有当workQueue队列填满时才会创建多于corePoolSize的线程(线程池总线程数不超过maxPoolSize)
keepAliveTime:非核心线程的空闲时间超过keepAliveTime就会被自动终止回收掉,注意当corePoolSize=maxPoolSize时,keepAliveTime参数也就不起作用了(因为不存在非核心线程);
unit:keepAliveTime的时间单位
workQueue:用于保存任务的队列,可以为无界、有界、同步移交三种队列类型之一,当池子里的工作线程数大于corePoolSize时,这时新进来的任务会被放到队列中
threadFactory:创建线程的工厂类,默认使用Executors.defaultThreadFactory(),也可以使用guava库的ThreadFactoryBuilder来创建
handler:线程池无法继续接收任务(队列已满且线程数达到maximunPoolSize)时的饱和策略,取值有AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy