线程池基本概念

通过Executors线程池工具类来使用:

  1. Executors.newSingleThreadExecutor():创建只有一个线程的线程池
  2. Executors.newFixedThreadPool(int):创建固定线程的线程池
  3. newScheduledThreadPool 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
  4. Executors.newCachedThreadPool():创建一个可缓存的线程池,线程数量随着处理业务数量变化。
  • 使用Executors.newCachedThreadPool()创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newCachedThreadPool 将 corePoolSize 设置为0,将 maximumPoolSize 设置为 Integer.MAX_VALUE,使用的 SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。

线程池参数

  • corePoolSize: 线程池中的常驻核心线程数,可理解为初始化线程数
  • maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1
  • threadFactory:线程工厂;表示生成线程池中工作线程的线程工厂,用于创建线程,一般用默认的即可
  • workQueue:任务队列;随着业务量的增多,线程开始慢慢处理不过来,这时候需要放到任务队列中去等待线程处理
  • rejectedExecutionHandler:拒绝策略;如果业务越来越多,线程池首先会扩容,扩容后发现还是处理不过来,任务队列已经满了,这时候拒绝接收新的请求
  • keepAliveTime:多余的空闲线程的存活时间;如果线程池扩容后,能处理过来,而且数据量并没有那么大,用最初的线程数量就能处理过来,剩下的线程被叫做空闲线程
  • unit:多余的空闲线程的存活时间的单位

        在创建了线程池后,等待提交过来的任务请求;当调用execute方法添加一个请求任务时,线程池会做如下判断:

  • 如果当前运行的线程数小于corePoolSize,那么马上创建线程运行该任务
  • 如果当前运行的线程数大于等于corePoolSize,那么该任务会被放入任务队列
  • 如果这时候任务队列满了且正在运行的线程数还小于maximumPoolSize,那么要创建非核心线程立刻运行这个任务(扩容)
  • 如果任务队列满了且正在运行的线程数等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行
  • 随着时间的推移,业务量越来越少,线程池中出现了空闲线程,当一个线程无事可做超过一定的时间时,线程池会进行判断:
  • 如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉,所以线程池的所有任务完成后它最终会收缩到 corePoolSize 的大小

四种拒绝策略
        在线程池中,如果任务队列满了并且正在运行的线程个数大于等于允许运行的最大线程数,那么线程池会启动拒绝策略来执行,具体分为下列四种:

  • AbortPolicy: 默认拒绝策略;直接抛出java.util.concurrent.RejectedExecutionException异常,阻止系统的正常运行;
  • CallerRunsPolicy:调用这运行,一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量;
  • DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入到队列中;
  • DiscardPolicy:直接丢弃任务,不给予任何处理也不会抛出异常;如果允许任务丢失,这是一种最好的解决方案;

合理配置线程池参数
        合理配置线程池参数,可以分为以下两种情况:

  • CPU密集型:CPU密集的意思是该任务需要大量的运算,而没有阻塞,CPU一直全速运行;

        CPU密集型任务配置尽可能少的线程数量:参考公式:(CPU核数+1)

  • IO密集型:即该任务需要大量的IO,即大量的阻塞;

        在IO密集型任务中使用多线程可以大大的加速程序运行,故需要多配置线程数:参考公式:CPU核数/ (1-阻塞系数) 阻塞系数在0.8~0.9之间

1. 线程池基本概念线程池作用:管理多个线程,避免频繁创建和销毁线程的开销 • 优势:提高性能,减少系统资源消耗 • 自动管理:线程的创建、执行和销毁都由线程池自动控制 2. 线程池核心方法 2.1 线程池配置 ```c# // 设置线程池最大线程数 bool result = ThreadPool.SetMaxThreads(10, 9); // 工作线程10个,I/O线程9个 // 获取线程池可用线程数 ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads); // 获取线程池最大线程数 ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads); ``` 2.2 添加工作项 ```c# // 无参数工作项 ThreadPool.QueueUserWorkItem(state => { Console.WriteLine("线程池开始工作"); }); //• 将一个无参数的Lambda表达式作为工作项添加到线程池队列 //• state参数是必须的,即使不使用也要声明 //• 当线程池中有可用线程时,会自动执行这个工作项 //• 适用于不需要外部数据的独立任务 // 带参数工作项 ThreadPool.QueueUserWorkItem(state => { Console.WriteLine("带有参数的池子:" + state); }, "我是参数"); //• 第一个参数:工作项回调函数(Lambda表达式) //• 第二个参数:传递给回调函数的数据("我是参数") //• 在回调函数内部通过state参数接收传递的数据 //• 适用于需要外部数据来执行的任务 ``` 执行流程: ​ 无参: ​ • 将工作项添加到线程池的任务队列中 ​ • 线程池在有可用线程时自动执行该工作项 ​ • 在线程池线程中执行Lambda表达式的内容 ​ • 输出"线程池开始工作"到控制台 ​ 有参: ​ • 将工作项添加到线程池队列中等待执行 ​ • 线程池分配可用线程来执行该工作项 ​ • 将"我是参数"这个字符串传递给state参数 ​ • 在工作线程中执行Lambda表达式,输出带参数的内容 共同特点: • 都是异步执行,不会阻塞主线程 • 由线程池自动管理线程的创建和执行 • 执行时机和顺序由线程池决定,开发者无法精确控制 1. 线程池工作原理 • 自动调度:线程池自动分配可用线程执行任务 • 执行顺序:任务按队列顺序执行,但具体执行顺序开发者无法干预 • 参数传递:通过QueueUserWorkItem的第二个参数传递数据 2. 线程池与普通线程的区别 特性 普通线程 线程池 创建方式 手动创建 自动管理 性能 较低(频繁创建销毁) 较高(复用线程) 资源消耗 较大 较小 控制性 手动控制 自动调度 3. 注意事项 • 线程池中的线程执行顺序不可控 • 适合执行短时间、独立的任务 • 不适合需要长时间运行或需要精确控制的线程 • 线程池会自动管理工作线程和I/O线程的数量
08-05
### 线程池基本概念 线程池是一种用于管理线程的机制,它维护着一组可重用的线程,这些线程可以被用来执行多个任务。这种方式避免了频繁创建和销毁线程所带来的开销,从而提高了应用程序的性能与响应速度。线程池特别适合处理大量短暂且独立的任务[^4]。 ### 线程池的核心方法 在C#中,`System.Threading.ThreadPool`类提供了对线程池的支持。一些常用的方法包括: - `QueueUserWorkItem`:将一个工作项排队到线程池中,该工作项将在某个线程池线程可用时执行。 - `RegisterWaitForSingleObject`:注册一个等待句柄,当指定的对象变为信号状态或超时间隔已过时,调用回调函数。 示例代码展示如何使用`QueueUserWorkItem`来提交任务给线程池: ```csharp // 使用 QueueUserWorkItem ThreadPool.QueueUserWorkItem(state => { Console.WriteLine($"Task executed on thread {Thread.CurrentThread.ManagedThreadId}"); // 长时间运行的任务 }); // 带参数的任务 ThreadPool.QueueUserWorkItem(obj => { var data = (string)obj; Console.WriteLine($"Processing: {data}"); }, "Hello ThreadPool"); ``` ### 线程池的工作原理 线程池内部维护了一个任务队列和一组工作者线程。当有新的任务被提交到线程池时,如果当前活动的线程数小于最小线程数,则会创建新的线程来处理任务;否则,任务会被放入队列中等待执行。一旦某个线程完成了它的任务,它就会从队列中取出下一个任务继续执行[^4]。 此外,线程池还能够根据系统的负载动态调整线程数量,以达到最优的资源利用率。例如,在计算密集型任务和I/O密集型任务混合的情况下,可以通过设置合适的线程数量来保证CPU的高效利用而不至于因为过多的上下文切换而降低性能[^3]。 ### 与普通线程的区别 - **生命周期管理**:普通线程需要显式地创建和销毁,而线程池中的线程是被复用的,它们在完成一个任务后不会立即终止,而是返回线程池准备执行下一个任务。 - **资源消耗**:每次创建和销毁线程都会有一定的系统资源开销,这在高频率的任务调度下尤为明显。线程池通过重用已存在的线程减少了这种开销。 - **调度效率**:线程池优化了线程的调度,使得任务可以更快地开始执行,因为不需要等待新线程的创建过程。 - **限制控制**:线程池通常提供了一些配置选项,允许开发者设置最大线程数、最小空闲线程数等参数,以便更好地适应特定的应用场景。 综上所述,线程池提供了一种更加高效且易于管理的方式来处理多线程任务。对于那些需要频繁启动短期运行任务的应用来说,使用线程池是一个非常好的选择。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值