Java并发-线程池API

本文介绍了Java四种线程池:newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool和newScheduledThreadPool的工作原理及参数配置。newFixedThreadPool具有固定线程数,newSingleThreadExecutor保证顺序执行,newCachedThreadPool可灵活回收线程,newScheduledThreadPool支持定时任务。理解线程池的使用有助于优化并发性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  今天小咸儿继续来分享对线程池的认知,这里介绍的是四种线程池:

  • newFixedThreadPool:该方法返回一个固定数量的线程池,线程数不变,当有一个任务提交时,若线程池中空闲,则立即执行,若没有,则会被暂缓在一个任务队列中,等待有空闲的线程去执行。
  • newSingleThreadExecutor:创建一个线程的线程池,若空闲则执行,若没有空闲线程则暂缓在任务队列中。
  • newCachedThreadPool:返回一个可根据实际情况调整线程个数的线程池,不限制最大线程数量,若用空闲的线程则执行任务,若无任务则不创建线程。并且每一个空闲线程会在60秒后自动回收(默认)
  • newScheduleThreadPool:创建一个可以指定线程的数量的线程池,但是这个线程池还带有延迟和周期性执行任务的功能,类似定时器。
ThreadPoolExecutor

  接下来先来看一下ThreadPoolExecutor类中构造方法中七大参数的含义:

public ThreadPoolExecutor(int corePoolSize,    // 核心线程数
                          int maximumPoolSize,   // 最大线程数
                          long keepAliveTime,    // 超时时间,当超出核心线程数时,多余线程的存活时间
                          TimeUnit unit,   // 存活时间的单位
                          BlockingQueue<Runnable> workQueue,  // 保存执行任务的队列
                          ThreadFactory threadFactory,  // 创建新线程使用的工厂
                          RejectedExecutionHandler handler //当任务无法执行的时候的处理方式) 
            {
                     // 其余实现
            }

  现在再来说一下线程池原理的基本流程,具体的详解还会见之后的源码:

  • 如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务。
  • 如果当前线程池中的线程数目大于或等于corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(可能是任务缓存队列已满),则会尝试创建新的线程去执行这个任务。
  • 如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理。
  • 如果线程池中的线程数量大于corePoolSize时,这时keepAliveTime开始起作用,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。

  线程池初始化是没有创建线程的,线程池里的线程初始化与其他的线程一样,但是在完成任务之后,该线程不会自动销毁,而是以挂起的状态返回到线程池,直到应用程序再次向线程池发送请求时,线程池里的线程就会再次激活去执行任务。这样既节省了创建和销毁线程的时间,还可以让多个任务重复调用同一个线程,从而在应用程序生存期内节省大量开销。

newFixedThreadPoolExecutor
/* @param nThreads the number of threads in the pool, 创建核心线程数和最大线程数的数量
 * @return the newly created thread pool
 * @throws IllegalArgumentException if {@code nThreads <= 0}
 */
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

  newFixedThreadPoolExecutor的核心线程数和最大线程数都是指定值,也就是nThreads。当线程池中的线程数超过核心线程数后,任务都会被放到阻塞队列中,而且从上述代码中也可以看出keepAliveTime为0,即超出核心线程数量以外的线程空闲时间为0。这里选用的阻塞队列是LinkedBlockingQueue,使用默认容量为Integer.MAX_VALUE。

newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

  newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲,若无可回收,则新建线程。并且没有核心线程数,最大线程数可达Integer.MAX_VALUE最大值,但是每个线程的空闲时间只有60s,超过后就会回收。使用的是SynchronousQueue。

newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

  newSingleThreadExecutor可以说是创建一个单线程化的线程池,它的corePoolSize和maximumPoolSize都为1,所以它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行(可以是FIFO先进先出,LIFO后进先出,或者是优先级),使用的是LinkedBlockingQueue。

  具体使用哪一种线程池可以参考自己的业务来,当然也可以继承ThreadPoolExecutor类进行重写以满足自己的业务需求。

参考文章1:ThreadPoolExecutor源码解析
参考文章2:线程池原理

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值