Java线程池详解:ThreadPoolExecutor、Executors

在操作系统中,线程是一个非常重要的资源,频繁创建和销毁大量线程会大大降低系统性能。Java线程池原理类似于数据库连接池,目的就是帮助我们实现线程复用,减少频繁创建和销毁线程。

ThreadPoolExecutor

ThreadPoolExecutor是线程池的核心类。首先看一下如何创建一个ThreadPoolExecutor。下面是ThreadPoolExecutor常用的一个构造方法:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)

参数介绍:

corePoolSize

核心线程数量,线程池刚创建时,线程数量为0,当每次执行execute添加新的任务时会在线程池创建一个新的线程,直到线程数量达到corePoolSize为止。

workQueue

阻塞队列,当线程池正在运行的线程数量已经达到corePoolSize,那么再通过execute添加新的任务则会被加到workQueue队列中,在队列中排队等待执行,而不会立即执行。

maximumPoolSize

最大线程数量,当workQueue队列已满,放不下新的任务,再通过execute添加新的任务则线程池会再创建新的线程,线程数量大于corePoolSize但不会超过maximumPoolSize,如果超过maximumPoolSize,那么会抛出异常,如RejectedExecutionException。

keepAliveTime和unit

当线程池中线程数量大于workQueue,如果一个线程的空闲时间大于keepAliveTime,则该线程会被销毁。unit则是keepAliveTime的时间单位。

总结一下线程池添加任务的整个流程:

  • 线程池刚刚创建是,线程数量为0;
  • 执行execute添加新的任务时会在线程池创建一个新的线程;
  • 当线程数量达到corePoolSize时,再添加新任务则会将任务放到workQueue队列;
  • 当队列已满放不下新的任务,再添加新任务则会继续创建新线程,但线程数量不超过maximumPoolSize;
  • 当线程数量达到maximumPoolSize时,再添加新任务则会抛出异常。

Executors

Executors提供了一些创建线程池的工具方法。

Executors.newSingleThreadExecutor()

源码实现:

new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

corePoolSize和maximumPoolSize都为1,也就是创建了一个固定大小是1的线程池,workQueue是new LinkedBlockingQueue<Runnable>()也就是队列的大小是Integer.MAX_VALUE,可以认为是队列的大小不限制。

扫描二维码关注公众号,回复: 2890625 查看本文章

由此可以得出通过该方法创建的线程池,每次只能同时运行一个线程,当有多个任务同时提交时,那也要一个一个排队执行。

Executors.newFixedThreadPool(int nThreads)

源码实现:

new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

类似Executors.newSingleThreadExecutor()也是创建了一个固定大小的线程池,但是可以指定同时运行的线程数量为nThreads。

Executors.newCachedThreadPool()

源码实现:

new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())

corePoolSize为0,maximumPoolSize为Integer.MAX_VALUE可以视为无穷大,workQueue是一个SynchronousQueue。SynchronousQueue可以认为是一个长度限制为0的队列,也就是向这个队列添加任务会永远是已满的状态。

由此可以得出通过该方法创建的线程池并不限制线程数量,每次添加的任务都会直接执行而不会放入workQueue,它的主要提供的功能是线程复用,但不能控制线程数量。

猜你喜欢

转载自blog.csdn.net/xiao__gui/article/details/51064317