并发编程(十三)线程池
一、线程池的分类
线程池的创建都是通过Executors(创建者接口)这个接口的方法进行创建的,下面我们来了解一下都有哪些线程池:
- newFixedThreadPool() : 创建一个固定线程的线程池
- newCachedThreadPool() : 创建一个可扩展的线程池。
- newScheduledThreadPool() : 创建一个可调度(周期执行)的线程池。
- newSingleThreadExecutor() : 创建一个单线程化(模拟队列)的线程池。
二、线程池实例分析
newFixedThreadPool【固定线程池】
语法:
//创建一个2个线程的线程池 ExecutorService fixedPool = Executors.newFixedThreadPool(2);
- 最多2个线程将处于活动状态。
- 如果提交了两个以上的线程,那么它们将保持在队列中,直到线程可用。
- 如果一个线程由于执行关闭期间的失败而终止,且执行器尚未被调用,则创建一个新线程。
- 线程会一直存在,直到池关闭。
实例:
/** * 固定线程的线程池 */ public class TestFixedThreadPool { public static void main(final String[] arguments) throws InterruptedException { //使用Executors(创建者接口创建一个固定两个线程的线程池) ExecutorService executor = Executors.newFixedThreadPool(2); //ExecutorService接口转换为线程池实例对象 ThreadPoolExecutor pool = (ThreadPoolExecutor) executor; //加入任务前的线程池状态 System.out.println("线程池大小: " + pool.getCorePoolSize()); System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize()); System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize()); System.out.println("线程池中当前线程的数量: " + pool.getPoolSize()); System.out.println("活动线程数: " + pool.getActiveCount()); System.out.println("已经分配执行的任务数: " + pool.getTaskCount()); //线程池中丢进两个线程 executor.submit(new TestThread()); executor.submit(new TestThread()); //加入任务后的线程池状态 System.out.println("线程池大小: " + pool.getCorePoolSize()); System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize()); System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize()); System.out.println("线程池中当前线程的数量: " + pool.getPoolSize()); System.out.println("活动线程数: " + pool.getActiveCount()); System.out.println("已经分配执行的任务数: " + pool.getTaskCount()); //关闭线程池 executor.shutdown(); } /** * 线程实体 */ static class TestThread implements Runnable { public void run() { try { Long duration = (long) (Math.random() * 5);//休眠时间,模拟线程内的工作 System.out.println("运行线程!线程名称为: " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(duration);//休眠 System.out.println("运行线程完毕!线程名称为: " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行结果:
newCachedThreadPool【可扩展线程池】
语法:
//创建一个可扩展线程池 ExecutorService executor = Executors.newCachedThreadPool();
- newCachedThreadPool()方法创建一个具有可扩展线程池的执行器。
- 核心线程数为零
- 最大线程数为无限
- 无任务时,线程存活的最大时间为60s
- 任务队列为同步移交队列,该队列没有缓冲区,即不会有任务会在该队列中排队,每当有任务要入队时,队列都会将任务移交给一个可用的线程
实例:
/** * 可扩展线程池 */ public class TestCachedThreadPool { public static void main(final String[] arguments) throws InterruptedException { //使用Executors(创建者接口创建一个可扩展线程池) ExecutorService executor = Executors.newCachedThreadPool(); //ExecutorService接口转换为线程池实例对象 ThreadPoolExecutor pool = (ThreadPoolExecutor) executor; //加入任务前的线程池状态 System.out.println("线程池大小: " + pool.getCorePoolSize()); System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize()); System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize()); System.out.println("线程池中当前线程的数量: " + pool.getPoolSize()); System.out.println("活动线程数: " + pool.getActiveCount()); System.out.println("已经分配执行的任务数: " + pool.getTaskCount()); System.out.println("=====开始加入线程====="); //线程池中丢进两个线程 executor.submit(new TestThread()); executor.submit(new TestThread()); System.out.println("=====加入线程完毕====="); //加入任务后的线程池状态 System.out.println("线程池大小: " + pool.getCorePoolSize()); System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize()); System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize()); System.out.println("线程池中当前线程的数量: " + pool.getPoolSize()); System.out.println("活动线程数: " + pool.getActiveCount()); System.out.println("已经分配执行的任务数: " + pool.getTaskCount()); //关闭线程池 executor.shutdown(); } /** * 线程实体 */ static class TestThread implements Runnable { public void run() { try { Long duration = (long) (Math.random() * 5);//休眠时间,模拟线程内的工作 System.out.println("运行线程!线程名称为: " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(duration);//休眠 System.out.println("运行线程完毕!线程名称为: " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行结果:
newScheduledThreadPool【可调度(周期执行)线程池】
//创建一个大小为2的可调度(周期执行)的线程池 ExecutorService executor = Executors.newScheduledThreadPool(2);
实例:
/** * 创建一个可调度(周期运行)的线程池。 * 此线程池支持定时以及周期性执行任务的需求。 */ public class TestScheduledThreadPool { public static void main(String[] args) { //使用Executors(创建者接口创建一个可调度的线程池) ScheduledExecutorService service = Executors.newScheduledThreadPool(2); System.out.println("=====观察周期线程实体(过了周期时间需检测上一个任务,执行完毕后才会接着执行)=====开始"); scheduleAtFixedRate(service, 1000);//由于执行时间在周期间隔内,每隔5秒会执行一次 scheduleAtFixedRate(service, 6000);//由于执行时间在周期间隔外,需等上一个任务执行完了以后才能继续执行,所以每隔6秒会执行一次 System.out.println("=====观察周期线程实体(过了周期时间需检测上一个任务,执行完毕后才会接着执行)=====结束"); System.out.println("=====观察周期线程实体(从上一个任务结束时间开始计时,过了周期时间立即执行下一个任务)=====开始"); scheduleWithFixedDelay(service, 1000);//周期为5秒,从任务结束开始计算周期,实际每个任务执行的间隔为5+1=6秒 scheduleWithFixedDelay(service, 6000);//周期为5秒,从任务结束开始计算周期,实际每个任务执行的间隔为5+6=11秒 System.out.println("=====观察周期线程实体(从上一个任务结束时间开始计时,过了周期时间立即执行下一个任务)=====开始"); } /** * 周期线程实体(过了周期时间需检测上一个任务,执行完毕后才会接着执行) * <p> * 执行步骤 * 1、是以上一个任务开始的时间计时 * 2、period时间过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行 * 3、如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行 */ private static void scheduleAtFixedRate(ScheduledExecutorService service, final int sleepTime) { service.scheduleAtFixedRate(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleAtFixedRate 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleAtFixedRate 执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleAtFixedRate 执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1000, 5000, TimeUnit.MILLISECONDS); } /** * 周期线程实体(从上一个任务结束时间开始计时,过了周期时间立即执行下一个任务) * <p> * 执行步骤 * 1、是以上一个任务结束的时间计时 * 2、period时间过去后,立即执行。 */ private static void scheduleWithFixedDelay(ScheduledExecutorService service, final int sleepTime) { service.scheduleWithFixedDelay(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleWithFixedDelay 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleWithFixedDelay执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1000, 5000, TimeUnit.MILLISECONDS); } }
newSingleThreadExecutor【单线程化(模拟队列)线程池】
语法:
//创建一个单线程化(模拟队列)的线程池 ExecutorService executor = Executors.newSingleThreadExecutor();
newSingleThreadExecutor()
方法创建一次执行单个任务的执行程序。- 此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
实例:
/** * 单例/线程化线程池【类似模拟一个队列去处理】 */ public class TestSingleThreadPool { public static void main(String[] args) { //使用Executors(创建者接口创建一个单例/线程化线程池) ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { String threadName = "我是序号为:" + (i + 1) + "的线程"; singleThreadExecutor.execute(new TestThread(threadName)); } singleThreadExecutor.shutdown(); System.out.println("main方法执行完毕,线程还在异步运行"); } /** * 线程实体 */ static class TestThread implements Runnable { private String threadName; public TestThread(String threadName) { this.threadName = threadName; } public void run() { try { System.out.println("运行线程!线程名称为: " + threadName); TimeUnit.SECONDS.sleep(3);//线程休眠3秒,模拟线程中处理的业务 System.out.println("运行线程完毕!线程名称为: " + threadName); System.out.println("========华丽的分割线========"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行结果:
参考资料:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律