java Executors是为了更好地帮助我们使用多线程编程
使用线程池的初衷
在需要使用的线程很多的情况下频繁创建线程、销毁线程是比较麻烦的事情,每个线程去完成占用时间较短的任务是很浪费资源的事情,如何做到让线程复用,使得线程完成任务之后并不马上销毁而是继续完成其他任务
线程池类ThreadPoolExecutor
线程池类构造器的构造参数:
corePoolSize:线程池的核心大小,也可以理解为最小的线程池大小,线程数达到该标准时,线程池自动把要完成的任务放进缓冲队列
maximumPoolSize:最多能创建多少个线程,也就是线程池的最大是多少
keepAliveTime:空余线程存活时间,指的是超过corePoolSize的空余线程达到多长时间才进行销毁。如果线程池中线程数量少于corePoolSize时并不会触发keepAliveTime的计算,但是超过线程池大小时当有空余线程空闲的时间keepAliveTime那么会被终止
但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0
workQueue:存储等待执行线程的工作队列。
threadFactory:创建线程的工厂,一般用默认即可。
handler:拒绝策略,当工作队列、线程池全已满时如何拒绝新任务,默认抛出异常。
unit:keepAliveTime的时间单位
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
线程类的方法
execute()
submit()
shutdown()
shutdownNow()
线程池的关闭
shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
线程池工作流程
线程池工作流程:
1、如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务
2、如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一般来说是任务缓存队列已满),则会尝试创建新的线程去执行这个任务,这个时候线程池中的线程数小于maximumPoolSize
3、如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理,这个时候缓冲队列不允许有新的任务了
4、如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,也就是allowCoreThreadTimeOut(true),那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止
线程池使用
Java本身不建议我们直接使用ThreadPoolExecutor来初始化新的线程池,Executors提供以下四种静态方法帮助我们初始化线程池,也就是说初始化一个线程池不一定需要配置那么多的参数
newCachedThreadPool 初始化一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。线程池本身可以无限扩大,也就是不存在缓冲队列
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。存在缓冲队列
但是任务完成后线程池不会自动关闭
newScheduledThreadPool创建大小无限但有核心容量的线程池,并支持定时任务
newSingleThreadExecutor创建单例线程池创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。