多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 介绍 经常会使用线程来处理异步任务,但是每个线程的创建和销毁都是有一定的开销,如果每次执行一个任务都需要开一个新的线程去执行,则这些线程创建和销毁将消耗大量的资源,并且很难控制。 Java 提供了 Executor 框架用于把任务的提交和执行解耦,任务的提交交给 Runnable 或者 Callable,而 Executor 用来处理任务,Executor 框架用来处理任务。Executor 框架中最核心的成员就是 ThreadPoolExecutor ,它是线程池的核心实现类。 ## ThreadPoolExecutor 可以通过 ThreadPoolExecutor 来创建一个线程池,ThreadPoolExecutor 类一共有四个构造方法,其中拥有最多参数的构造方法: ```java public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) ``` - corePoolSize 核心线程数,默认情况下线程池是空的,只有任务提交时才会创建线程。如果当前运行的线程数少于 corePoolSize,则创建新线程来处理任务;如果等于或者大于 corePoolSize ,则不再创建新线程。如果调用线程池的 prestartAllcoreThread方法,则线程池会提前创建并启动所有的核心线程来等待任务。 - maximumPoolSize:线程池允许创建的最大线程数。如果任务队列满了并且线程数小于 maximumPoolSize ,则线程池仍会创建新的线程来处理任务。 - keepAliveTime 非核心线程闲置的超时时间,超过这个时间则回收。如果任务很多,并且每个任务的执行时间很短,则可以调大 keepAliveTime 来提高线程的利用率。另外如果设置 allowCoreThreadTimeOut 为 true,keepAliveTime 也会应用到核心线程上。 - unit keepAliveTime的时间单位。 - workQueue 任务队列,如果当前的线程数大于 corePoolSize,则将任务添加到此任务队列中。该任务队列是 BlockindQueue (阻塞队列)类型的。 - threadFactory 线程工厂,可以用线程工厂给每个创建出来的线程设置名字,一般情况下不需要设置该参数 - handler 饱和策略,这是当前任务队列和线程池都满的时候采取的应对策略,默认是 AbordPolicy,表示无法处理新任务,并抛出 RejectExecutionException 异常,共四种策略,分别如下: 1. AbortPolicy(默认) : 抛出异常,并删除任务。 2. CallerRunsPolicy:用调用者所在的线程处理任务,此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。 3. DiscardPolicy:不执行任务,并将该任务删除 4. DiscardOldestPolicy :会抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。 流程图: ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610224214.png) ## 四种常见的线程池: ### 1、FixedThreadPool 可重用的固定线程数量的线程池。核心数量和最大数量一致。 ```java public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } ``` ```java Executor executor1 = Executors.newFixedThreadPool(2); ``` 线程数未达到核心数,则创建新的核心线程,否则加入无界队列 LinkedBlockingQueue。等待核心线程执行完任务去队列取任务。 ### 2、CachedThreadPool 没有核心线程,非核心线程无限的。有一个阻塞队列 SynchronousQueue。 ```java public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } ``` ```java Executor executor2 = Executors.newCachedThreadPool(); ``` 这里使用的是不存储元素的阻塞队列,所以有元素进入,必须立马取走,由于非核心线程又是最大的,所以相当于有任务进来就会别无限创建新的线程去执行,然后 60S 后自动销毁。 比较适合有大量任务需要立即处理并且耗时较少的任务。 ### 3、SingleThreadExecutor 只有一个线程 ```java public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } ``` ```java Executor executor3 = Executors.newSingleThreadExecutor(); ``` 没任务,就创建核心线程去执行 有任务,放入无界队列, SingleThreadExecutor 能够确保所有的任务在一个线程中按照顺序去执行。 ### 4、ScheduledThreadPool 创建一个定长的线程池,而且支持定时的以及周期性的任务执行。 ```java Executor executor4 = Executors.newScheduledThreadPool(1); ```