ThreadPoolExecutor线程池使用
线程池的作用:
线程池作用就是限制系统中执行线程的数量。
根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排 队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池 中有等待的工作线程,就可以开始运行了;否则进入等待队列。
为什么要用线程池:
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。
比较重要的几个类:
|
ExecutorService |
真正的线程池接口。 |
|
ScheduledExecutorService |
能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。 |
|
ThreadPoolExecutor |
ExecutorService的默认实现。 |
|
ScheduledThreadPoolExecutor |
继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。 |
要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。
ThreadPoolExecutor是什么
/** * Creates a new {@code ThreadPoolExecutor} with the given initial * parameters. * * @param corePoolSize the number of threads to keep in the pool, even * if they are idle, unless {@code allowCoreThreadTimeOut} is set(核心线程数,会一直存活即使没有任务需要执行,除非设置allowCoreThreadTimeOut=true核心线程会超时关闭) * @param maximumPoolSize the maximum number of threads to allow in the * pool(线程池中最大线程数) * @param keepAliveTime when the number of threads is greater than * the core, this is the maximum time that excess idle threads * will wait for new tasks before terminating.(线程空闲时间,当线程空闲时间达到keepAliveTime时,线程会退出直到数量达到corePoolSize,如果设置了allowCoreThreadTimeOut=true则数量退至0) * @param unit the time unit for the {@code keepAliveTime} argument(keepAliveTime的时间单位) * @param workQueue the queue to use for holding tasks before they are * executed. This queue will hold only the {@code Runnable} * tasks submitted by the {@code execute} method.(任务执行之前保存任务的队列,队列只保存由execute提交的Runnable任务) * @param threadFactory the factory to use when the executor * creates a new thread(线程创建工厂) * @param handler the handler to use when execution is blocked * because the thread bounds and queue capacities are reached(任务阻塞后的拒绝策略) * @throws IllegalArgumentException if one of the following holds:<br> * {@code corePoolSize < 0}<br> * {@code keepAliveTime < 0}<br> * {@code maximumPoolSize <= 0}<br> * {@code maximumPoolSize < corePoolSize} * @throws NullPointerException if {@code workQueue} * or {@code threadFactory} or {@code handler} is null */ 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; }
执行顺序
- 当线程数小于核心线程数时,创建线程进行处理。
- 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
- 当线程数大于等于核心线程数,且任务队列已满
- 若线程数小于最大线程数,创建线程
- 若线程数等于最大线程数,抛出异常,拒绝任务
初始化使用

Java四种线程池与ThreadPoolExecutor的关联
现有封装好的线程池:

- newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
- newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
(1)newFixedThreadPool
/** * Creates a thread pool that reuses a fixed number of threads * operating off a shared unbounded queue. At any point, at most * {@code nThreads} threads will be active processing tasks. * If additional tasks are submitted when all threads are active, * they will wait in the queue until a thread is available. * If any thread terminates due to a failure during execution * prior to shutdown, a new one will take its place if needed to * execute subsequent tasks. The threads in the pool will exist * until it is explicitly {@link ExecutorService#shutdown shutdown}. * * @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>()); }
从以上可以看出,
- corePoolSize与maximumPoolSize相等,即其线程全为核心线程,是一个固定大小的线程池,是其优势;
- keepAliveTime = 0 该参数默认对核心线程无效,而FixedThreadPool全部为核心线程;
- workQueue 为LinkedBlockingQueue(无界阻塞队列),队列最大值为Integer.MAX_VALUE。如果任务提交速度持续大余任务处理速度,会造成队列大量阻塞。因为队列很大,很有可能在拒绝策略前,内存溢出。是其劣势;
- FixedThreadPool的任务执行是无序的;
适用场景:可用于Web服务瞬时削峰,但需注意长时间持续高峰情况造成的队列阻塞。
(2)newSingleThreadExecutor
/** * Creates an Executor that uses a single worker thread operating * off an unbounded queue. (Note however that if this single * thread terminates due to a failure during execution prior to * shutdown, a new one will take its place if needed to execute * subsequent tasks.) Tasks are guaranteed to execute * sequentially, and no more than one task will be active at any * given time. Unlike the otherwise equivalent * {@code newFixedThreadPool(1)} the returned executor is * guaranteed not to be reconfigurable to use additional threads. * * @return the newly created single-threaded Executor */ public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
从以上可以看出,
- 单线程化的线程池,corePoolSize=maximumPoolSize=1,只有一个线程在执行,如果等待队列满了就直接拒绝执行新任务
- 为什么还要用线程池,只能是在一般情况下它是和单线程没区别的,但是如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。这一点是单线程没办法做到的
- 单线程线程池和定长线程池的阻塞队列使用的偶数LinkedBlockingQueue,默认的大小是int的最大值
(3)newCachedThreadPool
/** * Creates a thread pool that creates new threads as needed, but * will reuse previously constructed threads when they are * available. These pools will typically improve the performance * of programs that execute many short-lived asynchronous tasks. * Calls to {@code execute} will reuse previously constructed * threads if available. If no existing thread is available, a new * thread will be created and added to the pool. Threads that have * not been used for sixty seconds are terminated and removed from * the cache. Thus, a pool that remains idle for long enough will * not consume any resources. Note that pools with similar * properties but different details (for example, timeout parameters) * may be created using {@link ThreadPoolExecutor} constructors. * * @return the newly created thread pool */ public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
从上看出:
- corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即线程数量几乎无限制;
- keepAliveTime = 60s,线程空闲60s后自动结束。
- workQueue 为 SynchronousQueue 同步队列,这个队列类似于一个接力棒,入队出队必须同时传递,因为CachedThreadPool线程创建无限制,不会有队列等待,所以使用SynchronousQueue;
(4)newScheduledThreadPool
/**第一步 * Creates a thread pool that can schedule commands to run after a * given delay, or to execute periodically. * @param corePoolSize the number of threads to keep in the pool, * even if they are idle * @return a newly created scheduled thread pool * @throws IllegalArgumentException if {@code corePoolSize < 0} */ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } /**第二步 * Creates a new {@code ScheduledThreadPoolExecutor} with the * given core pool size. * * @param corePoolSize the number of threads to keep in the pool, even * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @throws IllegalArgumentException if {@code corePoolSize < 0} */ public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); } //第三步 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } //第四步 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; }
适合场景:周期性执行并发任务情况。
ThreadPoolExecutor自定义使用
import java.util.Date; import java.util.concurrent.*; public class Test { //线程池 线程数目 private static int ipTpsExecutorPoolCoreSize = 5; //线程池 最大排队数量,当请求过多时阻塞调用线程 private static int ipTpsExecutorPoolMaxSize = 5; //线程池 private static ExecutorService ipTpsExecutor; public static void test(final String ip) { ipTpsExecutor.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+ip); } }); } public static void main(String[] args) { ipTpsExecutor = new ThreadPoolExecutor(ipTpsExecutorPoolCoreSize, ipTpsExecutorPoolMaxSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); System.out.println("自定义ThreadPoolExecutor开始"+new Date()); for(int i = 0;i<ipTpsExecutorPoolMaxSize+10;i++) { test(",ip:"+i); } ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); System.out.println("newScheduledThreadPool,延迟3s开始"+new Date()); scheduledExecutorService.schedule(new Runnable() { @Override public void run() { System.out.println("schedule run "+new Date()); } }, 3, TimeUnit.SECONDS); ScheduledExecutorService es = Executors.newScheduledThreadPool(5); System.out.println("newScheduledThreadPool,延迟2s开始时间每三秒执行一次"+new Date()); Runnable syncRunnable = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+new Date()); } }; es.scheduleAtFixedRate(syncRunnable, 2000, 3000, TimeUnit.MILLISECONDS); } }
输出结果:
自定义ThreadPoolExecutor开始Wed Jan 20 14:36:54 CST 2021 pool-1-thread-2,ip:1 pool-1-thread-1,ip:0 pool-1-thread-2,ip:5 pool-1-thread-2,ip:6 pool-1-thread-1,ip:7 pool-1-thread-2,ip:8 pool-1-thread-1,ip:9 pool-1-thread-2,ip:10 pool-1-thread-1,ip:11 pool-1-thread-3,ip:2 pool-1-thread-5,ip:4 pool-1-thread-2,ip:12 pool-1-thread-3,ip:14 pool-1-thread-1,ip:13 pool-1-thread-4,ip:3 newScheduledThreadPool,延迟3s开始Wed Jan 20 14:36:54 CST 2021 newScheduledThreadPool,延迟2s开始时间每三秒执行一次Wed Jan 20 14:36:54 CST 2021 pool-3-thread-1Wed Jan 20 14:36:56 CST 2021 schedule runWed Jan 20 14:36:57 CST 2021 pool-3-thread-1Wed Jan 20 14:36:59 CST 2021 pool-3-thread-2Wed Jan 20 14:37:02 CST 2021 pool-3-thread-1Wed Jan 20 14:37:05 CST 2021 pool-3-thread-3Wed Jan 20 14:37:08 CST 2021 pool-3-thread-3Wed Jan 20 14:37:11 CST 2021 pool-3-thread-3Wed Jan 20 14:37:14 CST 2021 pool-3-thread-3Wed Jan 20 14:37:17 CST 2021 pool-3-thread-3Wed Jan 20 14:37:20 CST 2021 pool-3-thread-3Wed Jan 20 14:37:23 CST 2021 pool-3-thread-3Wed Jan 20 14:37:26 CST 2021 pool-3-thread-3Wed Jan 20 14:37:29 CST 2021 pool-3-thread-3Wed Jan 20 14:37:32 CST 2021 pool-3-thread-3Wed Jan 20 14:37:35 CST 2021 pool-3-thread-3Wed Jan 20 14:37:38 CST 2021 pool-3-thread-3Wed Jan 20 14:37:41 CST 2021 pool-3-thread-3Wed Jan 20 14:37:44 CST 2021 pool-3-thread-3Wed Jan 20 14:37:47 CST 2021 pool-3-thread-3Wed Jan 20 14:37:50 CST 2021 pool-3-thread-3Wed Jan 20 14:37:53 CST 2021 pool-3-thread-5Wed Jan 20 14:37:56 CST 2021 pool-3-thread-5Wed Jan 20 14:37:59 CST 2021 pool-3-thread-5Wed Jan 20 14:38:02 CST 2021 Process finished with exit code -1

浙公网安备 33010602011771号