🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
> ### 线程池的优点 1. 提升性能:它们通常在执行大量异步任务时,由于减少了每个任务的调用开销,并且它们提供了一种限制和管理资源(包括线程)的方法,使得性能提升明显; 2. 统计信息:每个ThreadPoolExecutor保持一些基本的统计信息,例如完成的任务数量。 > ### 线程池实现 - Executors提供的几种线程池: 1. FixedThreadPool:它是一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。由于FixedThreadPool只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速地响应外界的请求。 ``` // 实现方法 规定了核心和最大线程池大小,并使两者一致,使用无界队列(LinkedBlockingQuene)。 public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } ``` 2. CachedThreadPool:是一种线程数量不定的线程池,它只有非核心线程,并且其最大线程数为Integer.MAX_VALUE。从CachedThreadPool的特性来看,这类线程池比较适合执行大量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候CachedThreadPool之中实际上是没有任何线程的,它几乎是不占用任何系统资源的。 ``` // 实现方法 核心线程池为0,最大线程池无界,使用无缓存队列(SynchronousQuene)。 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } ``` 3. ScheduledThreadPool:它的核心线程数是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立即回收。只要用于执行定时任务和具有固定周期的重复任务。 ``` // 实现方法 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); } ``` 4. SingleThreadExecutor:该线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor的意义在于统一所有的外界任务到一个线程中,这使得在这些人物之间不需要处理线程同步问题。 ``` // 实现方法 规定核心、最大线程池数量都为1,使用无界队列(LinkedBlockingQuene), 且线程池相关参数不可改变 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));} ``` * 自定义实现线程池: 继承`ThreadPoolExecutor`并提供一个可以传入`corePoolSize`、`maxPoolSize`、`watiTime`、`timeUnit`、`blockingDeque`、`threadFactory`、`rejectPolicy`等相关参数的构造器。 ``` /** * @param corePoolSize:核心线程数量 * @param maxPoolSize:最大线程数量 * @param watiTime:空闲线程等待时间 * @param timeUnit:时间单位 * @param blockingDeque:等待队列 * @param threadFactory:线程工厂 * @param rejectPolicy:拒绝策略 **/ public void createThread(int corePoolSize, int maxPoolSize, long watiTime, TimeUnit timeUnit, BlockingDeque blockingDeque, ThreadFactory threadFactory, RejectedExecutionHandler rejectPolicy){ // 生成一个线程池 (同时可以使用其提供的两个钩子来定义线程执行前后的代码) ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, watiTime, timeUnit, blockingDeque, threadFactory, rejectPolicy){ public void beforeExecute(Runnable r, Throwable t){ // 线程执行前 } public void afterExecute(Runnable r, Throwable t){ // 线程执行后 } }; // 执行 threadPoolExecutor.execute(new Runnable(){ public void run(){ // 线程执行代码 } }); // 关闭线程池 等待所有正在执行及等待队列的线程执行完毕后关闭 threadPoolExecutor.shutdown(); } ``` > ### 线程池中线程执行顺序 ![](https://img.kancloud.cn/8c/c5/8cc5034dd1acaab9fe1e4c54ab838fea_1238x446.png) ``` 任务--->核心线程池--->等待线程池--->最大线程池---->拒绝策略 ``` 1. 任务到核心线程池看是否有少于核心线程数量(corePoolSize)的线程正在运行,如果有,即使其他工作线程处于空闲状态,也会创建一个新线程来处理该请求。 2. 如果核心线程池全都在工作状态,查看等待队列(blockingDeque)是否已经满了,未满该线程加入到等待队列。 3. 如果等待队列已经满了,查看最大线程池(maxPoolSize)是否已经满了,没有就新建一个线程立刻执行,直到超过最大线程池数量。 4. 如果超出最大线程池了,则执行拒绝策略(RejectedExecutionHandler)。 > ### 等待队列 - 等待队列的类型有四种: 1.ArrayBlockingQueue:有边界的数组阻塞队列,FIFO(先进先出),当超过边界时,则执行相应的拒绝策略。 2.LinkedBlockingQuene:无边界的阻塞队列,当超过corePoolSize时,会一直创建线程,然后再从队列中执行任务,相当于maximumPoolSize无效。 3.SynchronousQuene:无缓存队列,生产者产生一个任务到队列,必须有一个任务从队列中被执行,也就是说新的任务进来时,会创建线程来执行,当线程数超过maximumPoolSize时,执行拒绝策略。 4.PriorityBlockingQueue:具有优先级的无边界队列,根据参数comparator实现。 > ### 拒绝策略 - ThreadPoolExecutor 静态内部类提供4种拒绝策略: 1. AbortPolicy 直接报错 2. CallerRunsPolicy 直接执行Runnable里的run方法,该策略有可能造成主线程的阻塞 3. DiscardPolicy 什么也不做,不报错,也不执行。 4. DiscardOldestPolicy 最先进入队列的线程出队,然后ThreadPoolExecutor再执行该线程。 - 自定义拒绝策略 实现 RejectedExecutionHandler 并重写其 rejectedExecution(Runnable r, ThreadPoolExecutor e) 方法;