【第九章】JUC之ThreadPoolExecutor线程池详解

mac2026-01-01  0

一、线程池简介

  线程池主要是为了控制运行的线程数量,处理过程中将任务放到队列中,然后在线程创建后启动这些任务,如果线程数超过了最大数量,超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。

线程池主要特点是:线程复用、控制最大并发数(削峰操作)、管理线程。

二、如何使用线程池?

  Java中的线程池是通过Executor框架实现的,该框架中用到了Executor、Executors、ExecutorsService、ThreadPoolExecutor类。

三个常用的线程池

实现方法描述Executors.newFixedThreadPool(int)一池n个固定线程Executors.newSingleThreadExecutor()一池单线程Executors.newCachedThreadPool()可扩容线程
(1)Executors.newFixedThreadPool(int)代码实现
package com.lindaxia.juc.demo; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 线程池案例 * @author lindaxia * @date 2019/11/1 18:20 */ public class MyThreadPoolDemo { public static void main(String[] args) { System.out.println(); //创建一池n线程数--一个银行网点3个窗口 ExecutorService threadPool = Executors.newFixedThreadPool(3); try { for (int i = 1; i <=6; i++) { threadPool.execute( ()->{ System.out.println(Thread.currentThread().getName()+"\t号服务员提供服务"); } ); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown();//关闭线程池 } } }
测试结果

(2)Executors.newSingleThreadExecutor()代码实现
// ExecutorService threadPool = Executors.newFixedThreadPool(3); //一池单线程也能完成多任务 ExecutorService threadPool = Executors.newSingleThreadExecutor();
测试结果

(3)Executors.newCachedThreadPool()代码实现
//一池多线程(一个银行网点3个窗口) // ExecutorService threadPool = Executors.newFixedThreadPool(3); //一池单线程(一个银行网点1个窗口) //ExecutorService threadPool = Executors.newSingleThreadExecutor(); //池扩展线程(一个银行网点可扩展窗口) ExecutorService threadPool = Executors.newCachedThreadPool();
(1、2、3)方法底层实现源码

三、线程池底层工作原理(非常重要!!!)

(1)7大参数
参数描述corePoolSize线程池中的常驻核心线程池(new不会创建,Execute执行任务的时候创建,延迟加载,常驻线程池!!!)maximumPoolSize线程池中能容纳同时执行的最大线程数,此值必须>=1;keepAliveTime多余的空闲线程的存活时间,当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程会被销毁直到只剩下corePoolSize个线程为止unitkeepAliveTime的单位workQueue任务队列,被提交但尚未被执行的任务threadFactory生成线程池中工作线程的线程工厂,用于创建线程,一般默认的就行handler拒绝策略,当队列满了,并且工作线程>=线程池的最大线程(maximumPoolSize),拒绝请求执行runnable的策略

java.util.concurrent Class ThreadPoolExecutor 源码

(2)原理流程
①创建线程池后,线程池中的线程数为0【惰性加载】; ②当调用`execute()`方法添加一个请求任务时,线程池会做出如下判断:

  如果正在运行的线程数量小于corePoolSize,那么马上创建线 程运行这个任务;   如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列;   如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;    如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。 ③当一个线程完成任务时,它会从队列中取下一个任务来执行。 ④当一个线程空闲、超过一定的时间(keepAliveTime)时,线程会判断:如果当前运行线程数大于corePoolSize,那么这个线程就被停掉。当线程池的所有任务完成后,它最终会收缩到corePoolSize的大小【自动调节池大小】。

四、手写线程池

  线程池不允许使用Executors创建,而是通过ThreadPoolExecutor的方式,避免资源耗尽的风险!

  FixedThreadPool和singleThreadPool允许请求队列的长度Integer.MAX_VALUE,可能会堆积大量的请求(高并发高访问量)会导致OOM,(LinkedBlockingQueue链表有界阻塞队列的长度2 的 31 次方 - 1 = 2147483648 - 1 = 2147483647,运行程序的内存是有限的,所以提供的三个线程池不要使用,我们手写线程池!

(1)线程池的拒绝策略

  等待队列已满,再也塞不下新任务,同时,线程池中的最大线程数也达到极限,这时就无法继续为新任务服务。我们就需要拒绝策略机制合理的处理这个问题!

(2)JDK内置拒绝策略种类

以下策略都实现了RejectedExecutorHandle接口!

拒绝策略描述AbortPolicy(默认)直接抛出RejectedExecutionException异常阻止系统正常运行CallerRunsPolicy“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者(main线程),从而降低新任务的流量【吞吐量最大】DiscardOldestPolicy抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务【适合时效性的系统】DiscardPolicy该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略
(3)手写线程池代码
package com.lindaxia.juc.demo; import java.util.concurrent.*; /** * 线程池案例 * 拒绝策略(默认):AbortPolicy * @author lindaxia * @date 2019/11/1 18:20 */ public class MyThreadPoolDemo { public static void main(String[] args) { ExecutorService threadPool = new ThreadPoolExecutor( 2, //核心线程数2 5, //最大线程数5 3L, //多余线程的空闲超时时间 TimeUnit.SECONDS, //单位秒 new ArrayBlockingQueue<Runnable>(3),//数组有界阻塞队列3个 Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() //默认拒绝策略,超出最大线程数就会报异常 ); try { //3、5、8个任务,线程成功处理,9个任务已超出等待队列的容量就会抛异常 for (int i = 1; i <= 9; i++) { threadPool.execute( //执行任务才会常见线程池 () -> { System.out.println(Thread.currentThread().getName() + "\t号服务员提供服务"); } ); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown();//关闭线程池 } } }

打印结果1

测试结果2

#轻松一刻:

 ☝上述分享来源个人总结,如果分享对您有帮忙,希望您积极转载;如果您有不同的见解,希望您积极留言,让我们一起探讨,您的鼓励将是我前进道路上一份助力,非常感谢!我会不定时更新相关技术动态,同时我也会不断完善自己,提升技术,希望与君同成长同进步!

☞本人博客:https://coding0110lin.blog.csdn.net/  欢迎转载,一起技术交流吧!

最新回复(0)