首页 >> 知识 >> ThreadPoolExecutor线程池参数设置技巧

ThreadPoolExecutor线程池参数设置技巧

几种典型的线程池SingleThreadExecutor 单个线程线程池public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));}创建单个线程。它适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。

SingleThreadExecutor的corePoolSize和maximumPoolSize被设置为1,使用无界队列LinkedBlockingQueue作为线程池的工作队列。

当线程池中没有线程时,会创建一个新线程来执行任务。当前线程池中有一个线程后,将新任务加入LinkedBlockingQueue线程执行完第一个任务后,会在一个无限循环中反复从LinkedBlockingQueue 获取任务来执行。

**使用场景:**适用于串行执行任务场景

FixedThreadPool 创建一个线程数量固定的线程池,可控制线程最大并发数,超出的线程会在队列中等待。public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), threadFactory);}

corePoolSize等于maximumPoolSize,所以线程池中只有核心线程,使用无界阻塞队列LinkedBlockingQueue作为工作队列

FixedThreadPool是一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭。当所有的线程都处于活动状态时,新的任务都会处于等待状态,直到有线程空闲出来。

如果当前运行的线程数少于corePoolSize,则创建新线程来执行任务。在线程数目达到corePoolSize后,将新任务放到LinkedBlockingQueue阻塞队列中。线程执行完(1)中任务后,会在循环中反复从LinkedBlockingQueue获取任务来执行。

使用场景:适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。推荐:250期面试题汇总

CachedThreadPool 一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }

核心线程数为0,总线程数量阈值为Integer.MAX_VALUE,即可以创建无限的非核心线程

执行流程

先执行SynchronousQueue的offer方法提交任务,并查询线程池中是否有空闲线程来执行SynchronousQueue的poll方法来移除任务。如果有,则配对成功,将任务交给这个空闲线程否则,配对失败,创建新的线程去处理任务当线程池中的线程空闲时,会执行SynchronousQueue的poll方法等待执行SynchronousQueue中新提交的任务。若等待超过60s,空闲线程就会终止

流程形象图

结构形象图

使用场景:执行大量短生命周期任务。因为maximumPoolSize是无界的,所以提交任务的速度 > 线程池中线程处理任务的速度就要不断创建新线程;每次提交任务,都会立即有线程去处理,因此CachedThreadPool适用于处理大量、耗时少的任务。

ScheduledThreadPool 创建一个周期线程池,支持定时及周期性任务执行。public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize);}public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());}

线程总数阈值为Integer.MAX_VALUE,工作队列使用DelayedWorkQueue,非核心线程存活时间为0,所以线程池仅仅包含固定数目的核心线程。

两种方式提交任务:

scheduleAtFixedRate: 按照固定速率周期执行scheduleWithFixedDelay:上个任务延迟固定时间后执行

使用场景:周期性执行任务,并且需要限制线程数量的场景

使用无界队列的线程池会导致内存飙升吗?

答案 :会的,newFixedThreadPool使用了无界的阻塞队列LinkedBlockingQueue,如果线程获取一个任务后,任务的执行时间比较长,会导致队列的任务越积越多,导致机器内存使用不停飙升, 最终导致OOM。

 

ExecutorService executorService = new ThreadPoolExecutor( 5, 15, 30L, TimeUnit.SECONDS, new ArrayBlockingQueue(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() );

 

网站地图