为什么使用线程池?
1,降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2,提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行。
3,提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
如何创建线程池?
通过ThreadPoolExecutor来创建一个线程池。
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, timeUnit, runnableTaskQueue, handler);
corePoolSize - 核心池的大小。
maximumPoolSize - 线程池最大线程数,如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。
keepAliveTime - 当前线程数大于corePoolSize,小于maximumPoolSize时,超出corePoolSize的线程称为非核心线程,当非核心线程空闲keepAliveTime后,将会被销毁。
timeUnit - 线程活动保持时间的单位,DAYS,HOURS, MINUTES, MILLISECONDS
runnableTaskQueue - 任务等待队列,排队的策略时先进先出(FIFO),该任务队列需要继承Thread类或者实现Runnable接口。
线程池工作流程?
首先,线程池通过execute()方法执行某个任务(task),线程池收到这个任务后,
- 如果当前线程池中的线程数 < corePoolSize,无论之前已经创建的线程是否处于空闲状态,线程池会创建一个新的线程运行这个任务
- 如果当前线程池中的线程数 > = corePoolSize,线程池会把这个任务添加到等待队列(runnableTaskQueue)中。如果某一个线程空闲了,线程池根据规则从等待队列中取出一个任务执行。
- 如果当前线程池中的线程数 > corePoolSize, 并且等待队列已经满员,无法再加入新的任务,这时,线程池会创建一个非核心线程执行这个任务。
- 如果当前线程池中的线程数 = maximumPoolSize,新加入的这个任务会导致线程池抛出一个RejectedExecutionException异常,即线程池拒绝接收这个任务。
一旦线程池中某个线程完成了这个任务,它会去等待队列中拿下一个等待任务。
当线程池中的线程数 > corePoolSize,说明当前线程池中有非核心线程。当某个线程处理完线程后,等待keepAliveTime时间后仍然没有新的任务分配给它,这个线程将会被回收。直到线程数 = corePoolSize时,回收停止。
如下图: