文章目录
八 线程池-需要关闭
https://www.cnblogs.com/jay-huaxiao/p/11454416.html
为什么使用线程池?
每次new Thread性能差;
线程缺乏统一的管理,可能无限制创建线程,导致占用系统过多资源而死机和OOM;
缺乏功能:如定时执行;
8.1 ThreadPoolExecutor
8.1.1 初始化参数讲解:
- corePoolSize:核心线程数,默认核心线程会一直存活,即使处于闲置状态也不会受keepAliveTime限制。
- maximumPoolSize:最大线程数,超过这个数的线程将被执行拒绝策略。当任务队列为没有设置大小的LinkedBlocking时,这个值无效。
- keepAliveTime:非核心线程的闲置超时时间,超过这个线程就会被自动回收。
- unit:指定keepAliveTime的单位,TimeUnit.SECONDS。将allowCoreThreadTimeOut设置为true时对corePoolSize生效。
- workQueue:任务队列,阻塞队列
- threadFactory:线程工厂,主要用来创建线程
- RejectedExecutionHandler:拒接策略,达到最大线程数的拒绝策略
ThreadPoolExecutor.AbortPolicy:RejectedExecutionException异常。丢弃任务并抛出异常,默认的。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
总结:处理任务的优先级,核心线程数、任务队列、最大线程数,如果三者都满了,使用handler处理被拒绝的任务。
例子:这样的过程说明,并不是先加入任务就一定会先执行。假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务 4 ~ 13 被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,而任务 17~20 则会抛出异常。最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13
监控系统里可以用,统计一下每分钟
- getTaskCount:线程池已执行和未执行的任务总数
- getCompletedTaskCount:已完成的任务数量
- getPoolSize:线程当前的线程数量
- getActiveCount:当前线程中正在执行任务的线程数量
8.1.2 线程池的状态
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
几个重要的方法
execute(),submit(),shutdown(),shutdownNow()
- execute()实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,提交到线程池去执行。
- submit()是ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,ThreadPoolExecutor并没有对其重写。有返回值Future。execute+Furture
- shoutdown():关闭线程池,等待任务都执行完毕
- shoutdownNow():关闭线程池,不等待任务都执行完毕
8.1.3 线程池队列和常用线程池Executors
8.1.3.1 ThreadPoolExecutor的BlockingQueue
- SynchronousQueue:同步队列,一个不存储元素的阻塞队列。每个插入操作必须等待另一个线程调用移除操作
- LinkedBlockingQueue:无边界队列,是一个基于链表的阻塞队列。可设置容量队列,不设置的话,将是一个无边界的阻塞队列。
- ArrayBlockingQueue :有界队列,是一个基于数组结构的有界阻塞队列。先进先出队列。
- DelayQueue:延迟队列,是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后队列。
- PriortyBlockingQueue:优先级队列,是具有优先级的无界阻塞队列。
8.1.3.2 Executors
创建线程池的工具
- Executors.newCachedThreadPool 可缓存线程的线程池。底层:SynchronousQueue
- Executors.newFixedThreadPool 固定数目线程的线程池,。底层:LinkedBlockingQueue
- Executors.newScheduledThreadPool 定时及周期执行的线程池。底层:DelayQueue
- Executors.newSingleThreadPool 单线程执行,如果线程异常结束,会有另一个线程来取代它。底层:DelayedWorkQueue
8.1.4 Futrue
get方法:获取计算结果,一直会等待
cancel方法:还没计算完,可以取消计算过程
isDone方法:判断是否计算完
isCancelled方法:判断计算是否被取消
8.4 线程池合理配置
- cpu密集型任务,就需要尽量压榨cpu,参考值设置为cpu核数+1
- IO密集型的任务,参考值设置为2*CPU核数
任务计算的时间和任务的调度时间差不多时,就不要用线程池了。