一、通过Executors工厂来创建线程池(慎用)
Methods that create and return an ExecutorService set up with commonly useful configuration settings.
Methods that create and return a ScheduledExecutorService set up with commonly useful configuration settings.
Methods that create and return a "wrapped" ExecutorService, that disables reconfiguration by making implementation-specific methods inaccessible.
Methods that create and return a ThreadFactory that sets newly created threads to a known state.
Methods that create and return a Callable out of other closure-like forms, so they can be used in execution methods requiring Callable.
具体的工厂方法如下:
java.util.concurrent.Executors#newFixedThreadPool(int)
java.util.concurrent.Executors#newWorkStealingPool(int)
java.util.concurrent.Executors#newWorkStealingPool()
java.util.concurrent.Executors#newFixedThreadPool(int, java.util.concurrent.ThreadFactory)
java.util.concurrent.Executors#newSingleThreadExecutor()
java.util.concurrent.Executors#newSingleThreadExecutor(java.util.concurrent.ThreadFactory)
java.util.concurrent.Executors#newCachedThreadPool()
java.util.concurrent.Executors#newCachedThreadPool(java.util.concurrent.ThreadFactory)
java.util.concurrent.Executors#newSingleThreadScheduledExecutor()
java.util.concurrent.Executors#newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory)
java.util.concurrent.Executors#newScheduledThreadPool(int)
java.util.concurrent.Executors#newScheduledThreadPool(int, java.util.concurrent.ThreadFactory)
java.util.concurrent.Executors#unconfigurableExecutorService
java.util.concurrent.Executors#unconfigurableScheduledExecutorService
大体分为以下4类:
1、 newSingleThreadExecutor
创建一个单线程的线程池,保证所有任务按照提交顺序执行
适用:一个任务一个任务执行的场景
2、newFixedThreadPool
创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化
适用:执行长期的任务,性能好很多
3、newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
适用:执行很多短期异步的小程序或者负载较轻的服务器
4、 newScheduledThreadPool
创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
适用:周期性执行任务的场景
通常不使用这些工厂方法来创建线程池,原因是这些方法所使用的一些参数可能会产生严重的问题,在掌握下边的线程池方法参数的作用的前提下,去评估Executors所提供的方法是否可用。
二、 手动 new ThreadPollExecutor(xxx)
显式的通过构造方法来创建线程池。
image.png public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
1、corePoolSize(线程池基本大小):
- 当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize时。
- 除了利用提交新任务来创建和启动核心线程,也可以通过 prestartCoreThread() 或 prestartAllCoreThreads() 方法来提前启动线程池中的基本线程。
2、maximumPoolSize(线程池最大大小)
- 线程池所允许的最大线程个数。
- 当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。
- 对于无界队列,可忽略该参数
3、keepAliveTime、TimeUnit unit(线程存活保持时间)
- 当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数。
4、workQueue(任务队列)
- 阻塞队列,用于传输和保存等待执行的任务。
5、threadFactory(线程工厂)
- 用于创建新线程。
- threadFactory创建的线程是用new Thread()的方式
- 创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号,通俗理解就是几号池的几号线程)。
- 默认的线程工厂创建的线程是用户线程,优先级为正常优先级。
6、handler(线程饱和策略)
当线程池和队列都满了,再来任务会执行此策略。
线程池任务执行流程:
- 当线程池小于corePoolSize时,新提交任务将创建一个新线程来执行任务,即使此时线程池中存在空闲线程。
- 当线程池线程数量达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
- 当workQueue已满,且maximumPoolSize>corePoolSize时,对于新提交任务,线程池会创建新的线程来执行
- 当线程数超过maximumPoolSize时,且无空闲线程时,新提交任务由RejectedExecutionHandler处理
- 当线程池中线程数超过corePoolSize,若线程空闲时间达到keepAliveTime时,将被回收。
- 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
注意
- 如果使用无界LinkedBlockingQueue队列的话,因为队列大小没有限制,那么不会拒绝任何任务,ThreadPoolExecutor最多仅会按照最小线程数来创建线程,线程池大小被忽略了。所以要使用定长队列,要设置合理的线程数上线。
网友评论