一个普通的线程池

news/2024/12/29 2:16:13/

一个普通的线程池

    • 线程池的概念和作用
    • 线程池的工作原理
    • 线程池的参数和配置
    • 自己实现一个高可用线程池

线程池是并发编程中常用的一种技术,它可以有效地管理和复用线程,提高系统的性能和资源利用率。在深入讲解线程池的原理之前,我们先了解一下线程池的基本概念和作用。

线程池的概念和作用

线程池由一组线程组成的线程集合,它可以维护和管理这些线程的生命周期,并提供一种机制来控制线程的创建、执行和销毁。线程池的主要作用如下:

  1. 线程复用:线程池可以避免频繁地创建和销毁线程,而是通过复用已有的线程来执行任务。这样可以减少线程创建和销毁的开销,提高系统的性能。

  2. 线程管理:线程池可以统一管理和监控线程的状态、数量和执行情况。通过合理地调整线程池的参数,可以控制系统的并发度,防止线程数量过多导致系统资源耗尽。

  3. 任务调度:线程池可以将待执行的任务按照一定的调度策略分配给空闲的线程执行。这样可以实现任务的异步执行,提高系统的响应速度和吞吐量。

  4. 任务排队:线程池可以通过任务队列来存放待执行的任务,当线程池中的线程都在执行任务时,新的任务可以暂时排队等待执行,避免任务丢失或被拒绝。

线程池的工作原理

线程池的工作原理可以简单概括为以下几个步骤:

  1. 线程池初始化:在创建线程池时,需要指定线程池的大小和其他相关参数。线程池会预先创建一定数量的工作线程,并将它们置于待命状态,准备执行任务。

  2. 任务提交:当有任务需要执行时,可以通过向线程池提交任务来执行。任务可以是实现了Runnable接口或Callable接口的对象。

  3. 任务调度:线程池会选择一个空闲的工作线程来执行任务。如果没有空闲线程,任务会被暂时存放在任务队列中等待执行。

  4. 任务执行:被选中的工作线程会从任务队列中取出任务,并执行任务的run()方法。一旦任务执行完毕,线程会返回线程池,并等待下一个任务的分配。

  5. 任务拒绝和丢弃:如果任务队列已满且没有空闲线程,新提交的任务可能会被拒绝执行。线程池提供了一些策略来处理

这种情况,例如抛出异常、丢弃任务等。

  1. 线程池关闭:当不再需要线程池时,可以调用线程池的关闭方法来停止接受新的任务,并等待已有任务执行完毕。线程池会逐个关闭工作线程,并释放线程池占用的资源。

线程池的参数和配置

线程池的性能和行为可以通过一些参数来配置,常用的参数包括:

  1. 核心线程数(corePoolSize):线程池中始终保持的活动线程数量,即使它们处于空闲状态。这些线程会一直存活,除非设置了线程池的闲置超时时间。

  2. 最大线程数(maximumPoolSize):线程池中允许的最大线程数量。当任务队列已满且活动线程数达到最大线程数时,新提交的任务可能会触发拒绝策略。

  3. 任务队列(workQueue):用于存放待执行任务的队列。可以选择不同类型的队列,如无界队列、有界队列或同步队列,以适应不同的任务处理需求。

  4. 线程闲置时间(keepAliveTime):线程池中超过核心线程数的空闲线程的闲置时间。当线程处于空闲状态并且超过该时间时,它们会被终止并从线程池中移除。

  5. 拒绝策略(rejectedExecutionHandler):当任务无法被接受和处理时的处理策略。常见的策略包括抛出异常、丢弃任务、丢弃队列中最旧的任务等。

通过合理地配置这些参数,可以根据具体的应用场景和系统负载来优化线程池的性能和行为。

自己实现一个高可用线程池

自己实现一个高可用线程池可以帮助我们更好地理解线程池的工作原理和实现细节。在实现过程中,可以参考以下步骤:

  1. 定义线程池的参数和配置,如核心线程数、最大线程数、任务队列等。

  2. 创建一个线程池管理器,用于创建、管理和调度线程池。可以使用ThreadPoolExecutor类作为线程池管理器的基础。

  3. 实现任务队列,用于存放待执行的任务。可以选择适合场景的队列实现,如ArrayBlockingQueueLinkedBlockingQueue等。

  4. 定义任务类,实现Runnable接口或Callable接口。在任务类的run()方法中编写具体的任务逻辑。

  5. 在线程池管理器中实现任务

调度和执行的逻辑。根据线程池的配置参数,决定是否创建新的线程,将任务分配给空闲线程执行,或将任务放入任务队列等待执行。

  1. 实现线程池的关闭方法,用于停止接受新的任务,并等待已有任务执行完毕。可以使用shutdown()awaitTermination()方法来实现线程池的优雅关闭。
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;public class MyThreadPool {public static void main(String[] args) {// 创建自定义线程池ThreadPoolExecutor executor = createThreadPool();// 提交任务给线程池for (int i = 0; i < 20; i++) {executor.execute(new MyTask(i));}// 关闭线程池gracefulShutdown(executor);}private static ThreadPoolExecutor createThreadPool() {// 线程池参数int corePoolSize = 5; // 核心线程数int maxPoolSize = 10; // 最大线程数long keepAliveTime = 60L; // 线程闲置时间int queueCapacity = 100; // 任务队列容量// 创建任务队列BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueCapacity);// 创建线程工厂ThreadFactory threadFactory = new ThreadFactory() {private final AtomicInteger threadNumber = new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r);thread.setName("MyThreadPool-" + threadNumber.getAndIncrement());thread.setPriority(Thread.NORM_PRIORITY);return thread;}};// 创建拒绝策略RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,TimeUnit.SECONDS,workQueue,threadFactory,rejectedExecutionHandler);// 设置允许核心线程超时executor.allowCoreThreadTimeOut(true);return executor;}private static void gracefulShutdown(ThreadPoolExecutor executor) {executor.shutdown();try {if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {executor.shutdownNow();if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {System.err.println("线程池未能正常关闭");}}} catch (InterruptedException e) {executor.shutdownNow();Thread.currentThread().interrupt();}}static class MyTask implements Runnable {private int taskId;public MyTask(int taskId) {this.taskId = taskId;}@Overridepublic void run() {System.out.println("Task " + taskId + " is running.");try {// 模拟任务执行时间Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Task " + taskId + " is completed.");}}
}

通过自己实现一个高可用线程池,我们可以更深入地理解线程池的原理和内部机制。同时,也可以根据实际需求对线程池进行定制和优化,以满足不同的应用场景和性能要求。


http://www.ppmy.cn/news/314508.html

相关文章

汇总各种数据库越权操作的错误码

DB2数据库&#xff1a; 错误码&#xff1a; 01548 命名的授权ID缺少在命名的DB2对象上执行命名操作的权限 01542 命名的授权ID缺少执行命名操作的权限 01516 已经被授权该PUBLIC&#xff0c;因此WITH GRANT OPTION不可用 postgress数据库&#xff1a; 错误信息“Error 4…

Mac环境Royal TSX 从入门使用代替X sheet

Royal TSX 是一款 macOS 下可用的远程连接软件&#xff0c;类似于 Windows 系统的 XShell 。免费版最多支持 10 个连接&#xff0c;对于个人开发而言&#xff0c;已经足够了 一、下载安装 Royal TS 官网&#xff1a;https://www.royalapps.com/ts/win/download 选择 Royal T…

使用西储大学轴承故障数据遇到了一些问题,望道友指点迷津!

在网上下载了西储大学的轴承故障数据&#xff0c;也看了很多的说明但还是有几点不懂&#xff0c;望有道友指点&#xff01; 1.为什么在12k_Drive_End_B007_0_118文件用MATLAB打开时&#xff0c;里面又会有X118_BA_time、X118_DE_time、X118_FE_time、X118RPM。我知道X118RPM是指…

x++,x--,++x,--x

1&#xff0c;x和x在单独使用时没有区别 测试代码&#xff1a; int m2&#xff0c;n2; m; n; printf("%d\n%d",m ,n);输出结果&#xff1a;3 3 2&#xff0c;但当在其他代码中时会有区别 int m,n; m0; n m; printf("%d\n%d\n", n, m); printf("%d\…

Ricoh Theta X 评测

Theta X 是围绕两个 48MP 传感器和双镜头构建的&#xff0c;它们可以一起捕捉 60MP 球面照片或 5.7K/30p 视频。但其他 Theta 相机的可用性升级&#xff0c;如旗舰产品 Theta Z1&#xff0c;包括一个方便的 2.25 英寸触摸屏、可更换电池和可扩展内存。Ricoh Theta X更多使用感受…

怎么把.mat 转化成.csv格式

怎么把.mat 转化成.csv格式 首先load(‘yourfilename’) 其中yourfilename是matlab中的文件 然后再使用csvwrite(‘filename.csv’,yourfilename) 具体步骤如下&#xff1a; 1、 2、这里把X118_DE_time,转化成X118.csv文件 3、之后就转化成了X118.csv

babyos2(1)——boot

要做一个能在裸机上跑的系统&#xff0c;一个简单的boot loader或者是支持grub之类的是必须的。目前并没有把babyos装到实体机上、支持多系统等的打算&#xff0c;所以还是自己写boot loader。 PC上电后&#xff0c;80x86 CPU自动进入实模式&#xff0c;并从0xFFFF0开始自动执…