为什么有线程池?
java语言里,针对每个请求都创建一个线程,会有很大开销。计算机在创建和销毁线程都需要花费额外的时间,甚至多于处理用户请求的时间。创建过多线程还会导致线程切换以及消耗内存导致资源不足。所以需要一个东西来管理线程,充分利用资源。-- 线程池
线程池作用
- 降低资源消耗。重复利用已创建的线程,降低创建和销毁线程的开销
- 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立刻执行
- 提高线程的可管理性。使用线程池可以对线程进行统一的分配、调优和监控
java线程池分类
- newCachedThreadPool
作用:创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程。
创建方式: Executors.newCachedThreadPool()
- newFixedThreadPool
作用:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
创建方式: Executors.newFixedThreadPool(int nThreads)
- newSingleThreadExecutor
作用:创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newFixedThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。
创建方式: Executors.newSingleThreadExecutor()
- newScheduleThreadPool
作用: 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
创建方式: Executors.newScheduledThreadPool(int corePoolSize)
- newSingleThreadScheduledExecutor
作用: 创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
创建方式: Executors.newSingleThreadScheduledExecutor()
核心参数
- corePoolSize:线程池中的常驻核心线程数
- maximumPoolSize:线程池中能够容纳同时执行的最大线程数,必须大于1
- keepAliveTime:多余的空闲线程的存活时间;当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程会被销毁
- unit:keepAliveTime的单位
- workQueue:任务队列,被提交但尚未执行的任务
- threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认
- handler:拒绝策略,表示当队列满了,并且工作线程大于等于线程池的最大线程数时如何来拒绝请求执行的runnable的策略
工作中优雅使用
如果是基于spring开发,那么可以使用spring提供的线程池包装类。
- ThreadPoolTaskExecutor
@Bean("testExecutorPool")
public Executor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 核心池大小
taskExecutor.setCorePoolSize(5);
// 最大线程数
taskExecutor.setMaxPoolSize(10);
// 队列程度
taskExecutor.setQueueCapacity(100);
// 线程空闲时间
taskExecutor.setKeepAliveSeconds(60);
// 线程前缀名称
taskExecutor.setThreadNamePrefix("testExecutor--");
// 任务的等待时间 如果超过这个时间还没有销毁就 强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
taskExecutor.setAwaitTerminationSeconds(60);
// 线程不够用时由调用的线程处理该任务
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return taskExecutor;
}
- @Scheduled
@Async
@Scheduled(fixedRate = 500L)
public void scheduledTest() {
UUID id = UUID.randomUUID();
log.warn("Thread id: {}", id);
}