浅谈线程池及 Executors 框架

线程池是什么

线程池(Thread Pool)是一种线程使用模式。线程池维护着多个线程,等待调用者分配需要并发执行的任务。这避免了在处理耗时短的任务时创建与销毁线程的开销。线程池不仅能保证内核的充分利用,还能防止过分调度。线程池一般设置为 CPU+2 比较合适,线程过多会带来额外的调度开销。

线程池带来的好处

  • 重复利用线程,减少线程创建、销毁的开销,提高性能
  • 控制并发线程数,避免短时间创建大量线程导致系统资源耗尽和过度调度
  • 提供了定时、定期执行功能
  • 批量管理线程

线程池的潜在影响

  • 创建太多线程,将会浪费一定的资源,部分线程未被充分利用
  • 销毁太多线程,将导致之后浪费时间再次创建
  • 创建线程太慢,将会导致长时间等待,性能变差

线程池使用场景

  • 需要大量线程,且单个任务执行时间短
  • 对性能要求高,如完成快速响应
  • 接受突发的大量请求

线程池的创建方式

使用 Executors 框架创建

java.util.concurrent.ExecutorsJDK 默认提供的快速创建线程池的类,主要有以下 4 种方式

newSingleThreadExecutor

下面是源码

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

创建一个单线程的线程池,它使用一个工作线程在无界队列中运行。如果这个单线程在关闭之前由于执行失败而终止,并且需要去处理后续任务,将会产生一个新线程取代它。

单线程的线程池保证任务按顺序执行,并且保证在任何时间只有一个线程处于活动状态。

newFixedThreadPool

下面是源码

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

创建一个固定大小的线程池,该线程池重用固定数量的线程在共享的无界队列中运行。在任何时候,最多有 nThreads 个线程活动。如果在所有线程都处于活动状态时提交了新任务,将被放在队列中等待,直到有空闲线程可用。如果任何一个线程在关闭前的执行过程中因失败而终止,在后续需要执行任务时,将会产生一个新线程取代它。池中的线程将一直存在,直到线程池被明确的 shutdown

newCachedThreadPool

下面是源码

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

创建一个可缓存的线程池,将根据需要创建新线程,但在可用时优先重用之前的线程。如果没有可用的现有线程,将会新建一个线程并将其加入到池中。60s 内未使用的线程将被关闭,并且从缓存中删除。因此,保持空闲时间足够长的此类型线程池,将不会消耗任何资源。

newScheduledThreadPool

下面是源码

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

创建一个定时的线程池,可以安排任务在给定的延迟后运行,或定期执行。

如果上述的创建方式无法满足你的需求,还可以通过自定义线程参数的方式创建。Executors 也是通过调用 ThreadPoolExecutor 来创建的。

使用 ThreadPoolExecutor 自定义线程池

这种创建方式提供了以下 7 个参数供用户配置

corePoolSize

核心线程数,要保留在池中的线程数,即使它们处于空闲状态

maximumPoolSize

池中允许的最大线程数

keepAliveTime

当活动线程数大于核心线程数时,在多余空闲线程被终止前等待新任务的最大时间

TimeUnit

keepAliveTime 参数的时间单位

workQueue

在执行任务之前保存任务的队列

ThreadFactory

创建新线程的工厂

RejectedExecutionHandler

在达到线程数边界和队列容量时,对新任务的拒绝策略

posted @ 2021-08-21 00:23  超级鲨鱼辣椒  阅读(65)  评论(0编辑  收藏  举报