线程池
快来分享你的内容吧~
- 2025-02-02·Java后端
- 2024-12-13·Java后端
- 2024-07-18目前遇到一个线程池的场景 背景:通过@Bean注解声明了一个自定义的线程池,在项目中,跑任务方法会通过@Async注解指定该线程池进行异步执行。 问题:在服务宕机、掉电、重启场景中,怎么保证未执行完的测试中的任务能正常推进?让其正常执行完,或直接转为 失败的状态? 目前想到的通过定时任务扫表更新测试中状态,老表们有什么比较好的解决方法吗?查看全文鱼友0412:你在使用线程池的场景中遇到的问题很常见。为了确保线程池中任务的状态能正常推进,我建议你考虑以下几点:1. 确保任务的持久性:要保证任务在宕机、掉电、重启等场景中能够恢复并继续执行,你可以使用持久化技术,如将任务信息存储在数据库或消息队列中。当应用程序重新启动时,你可以从数据库或消息队列中读取未执行完的任务,并继续执行。2. 定时任务扫表更新状态:你可以使用定时任务来扫描数据库或消息队列,然后更新任410分享
哥你好,我想问下,线程池的线程哥你好,我想问下,线程池的线程数怎么确定,有什么方法或者工具吗?可以举个例子吗。...查看全文菜饼同学:你好,感谢提问~这是一个很好的问题,但是又略微有些大,其实不是那么好解答的。线程池的线程数怎么定,首先从原理上,要理解为什么有线程池的存在,其次线程数到底影响哪些东西?我们知道创建线程,销毁线程都是有成本的,而通过线程池,我们可以复用这池子里的线程去执行任务,这样就可以节省每次创建、销毁线程的成本。那么显而易见的,线程池的线程数量如何设置,就是一个很重要的问题。如果线程数量设置少了,那么后来的任务
哥你好,我想问下,线程池的线程哥你好,我想问下,线程池的线程数怎么确定,有什么方法或者工具吗?可以举个例子吗。...查看全文菜饼同学:你好,感谢提问~这是一个很好的问题,但是又略微有些大,其实不是那么好解答的。线程池的线程数怎么定,首先从原理上,要理解为什么有线程池的存在,其次线程数到底影响哪些东西?我们知道创建线程,销毁线程都是有成本的,而通过线程池,我们可以复用这池子里的线程去执行任务,这样就可以节省每次创建、销毁线程的成本。那么显而易见的,线程池的线程数量如何设置,就是一个很重要的问题。如果线程数量设置少了,那么后来的任务
关于线程池的学习
# 线程池 ## 为什么要引入线程池 1. 降低资源消耗 复用线程:频繁创建和销毁线程会消耗大量系统资源(如内存、CPU)。线程池通过复用已创建的线程,减少线程生命周期带来的开销。减少上下文切换:线程过多会导致CPU频繁切换线程上下文,线程池通过控制线程数量,降低切换频 率。提高线程池的复用性 2. 提高响应速度 任务即时处理:当任务到达时,线程池中通常已有空闲线程可直接执行任务,无需等待新线程创建,缩短任务延迟。 3. 控制并发规模 限制线程数量:通过设置核心线程数、最大线程数,防止无限制创建线程导致系统资源耗尽(如内存溢出)。流量削峰:突发大量任务时,队列缓存任务,线程池按配置逐步处理,避免瞬间高并发压垮系统。 4. 统一管理与监控 生命周期管理:线程池自动维护线程的创建、回收(如超时空闲线程销毁),简化开发。任务队列机制:支持多种队列(如无界队列、有界队列、优先级队列),灵活应对不同场景需求。统计与监控:可跟踪任务完成数、活动线程数等指标,便于优化和排查问题。 5. 增强稳定性 拒绝策略:当任务超出队列容量且线程数达上限时,提供拒绝策略(如丢弃、抛异常、调用者执行等),避免系统崩溃。异常处理:支持自定义异常处理逻辑(如记录日志、重试),防止任务失败导致线程终止。 ## 基于SpringBoot的线程池的引入 ```js package com.niki.mallchat.common.common.config; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; /** * @author niki * @date 2023/5/23 16:39 * @Description: 同一线程池的管理 */ @Slf4j @Configuration @EnableAsync public class ThreadPoolConfig { @Qualifier("threadPoolTaskExecutor") public ThreadPoolTaskExecutor threadPoolTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 设置核心线程数 executor.setCorePoolSize(10); // 设置最大线程数 executor.setMaxPoolSize(16); // 设置队列容量 executor.setQueueCapacity(200); // 设置线程池前缀 executor.setThreadNamePrefix("mallchat-executor-"); // 设置拒绝策略为CallerRunsPolicy executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 设置优雅停机,等待任务完成 executor.setWaitForTasksToCompleteOnShutdown(true); //设置等待的时间为60S executor.setAwaitTerminationSeconds(60); executor.initialize(); return executor; } } ``` 为了防止服务停机或者线程池停止导致当前的任务未执行 设置了**setWaitForTasksToCompleteOnShutdown**这个参数 默认为**false** <img src="https://pic.code-nav.cn/post_picture/1812294503704485890/MSLOTbGMLqogTTC7.webp" alt="image.png" width="100%" /> 这个类实现了**DisposableBea**n的方法 并且重写了**shutDown**方法 <img src="https://pic.code-nav.cn/post_picture/1812294503704485890/xMPLTgp9lc2KmsoK.webp" alt="image.png" width="100%" /> 我们在我们需要的地方打上**@Async这个注解并且指定Bean的名称**就可以使用当前线程池提高的线程执行异步化 ## 结尾 实现异步的方式还有很多 比如使用Java1.8并发包中的**CompletableFuture**等等 ```js import java.util.concurrent.CompletableFuture; public class CompletableFutureExample { public static void main(String[] args) { CompletableFuture.supplyAsync(() -> { // 第一个任务 return "Hello"; }).thenApplyAsync(result -> { // 第二个任务,依赖第一个任务的结果 return result + ", CompletableFuture!"; }).thenAcceptAsync(finalResult -> { // 消费最终结果 System.out.println(finalResult); // 输出: Hello, CompletableFuture! }).join(); // 等待任务完成 } } ```
动态配置线程池参数 - dynamic-tp
官网接入指南: [https://dynamictp.cn/guide/use/quick-start.html](https://dynamictp.cn/guide/use/quick-start.html) 1.新建一个spirng boot项目 ```java <properties> // jdk 版本为 1.8 <java.version>1.8</java.version> // spring boot版本为2.6.13 <spring-boot.version>2.6.13</spring-boot.version> </properties> ``` 2.导入dynamictp依赖 ```java // SpringBoot1x、2x 用此依赖 <dependency> <groupId>org.dromara.dynamictp</groupId> <artifactId>dynamic-tp-spring-boot-starter-adapter-rocketmq</artifactId> <version>1.1.9.1</version> </dependency> ``` 3.在启动类中开启dynamictp ```java package com.example.demo; import org.dromara.dynamictp.core.spring.EnableDynamicTp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication // 开启自动配置线程池参数 @EnableDynamicTp public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` ```java 2024-12-13 23:20:17.924 INFO 14024 --- [ main] org.dromara.dynamictp.core.DtpRegistry : DynamicTp register executor: TpMainFields(threadPoolName=dtpExecutor1, corePoolSize=20, maxPoolSize=40, keepAliveTime=60, queueType=VariableLinkedBlockingQueue, queueCapacity=1000, rejectType=CallerRunsPolicy, allowCoreThreadTimeOut=false), source: beanPostProcessor 2024-12-13 23:20:17.925 INFO 14024 --- [ main] org.dromara.dynamictp.core.DtpRegistry : DynamicTp register executor: TpMainFields(threadPoolName=threadPoolTaskExecutor, corePoolSize=20, maxPoolSize=40, keepAliveTime=400, queueType=VariableLinkedBlockingQueue, queueCapacity=1000, rejectType=CallerRunsPolicy, allowCoreThreadTimeOut=false), source: beanPostProcessor 2024-12-13 23:20:17.942 INFO 14024 --- [ main] o.d.d.core.support.DtpBannerPrinter : | __ (_) |__ __| | | | |_ _ _ __ __ _ _ __ ___ _ ___| |_ __ | | | | | | | '_ / _` | '_ ` _ | |/ __| | '_ | |__| | |_| | | | | (_| | | | | | | | (__| | |_) | |_____/ __, |_| |_|__,_|_| |_| |_|_|___|_| .__/ __/ | | | |___/ |_| :: Dynamic Thread Pool :: :: 1.1.9.1 :: :: https://dynamictp.cn :: :: https://github.com/dromara/dynamic-tp :: :: https://gitee.com/dromara/dynamic-tp :: ``` 看见dynamictp 的启动帧栈信息和banner图代表启动成功 4.修改application.yml文件 ```java server: port: 8080 #优雅停机 shutdown: graceful spring: dynamic: tp: #全局线程池配置 globalExecutorProps: #线程池的拒绝策略 rejectedHandlerType: CallerRunsPolicy #线程池的阻塞队列 这里使用的是LinkedBlockingQueue克隆版本具体可看源码注释 queueType: VariableLinkedBlockingQueue #线程池关闭后是否等待现有任务完成后关闭线程池 waitForTasksToCompleteOnShutdown: true # 线程池等待所有任务完成(或超时)的最长等待时间(以秒为单位) awaitTerminationSeconds: 3 executors: - threadPoolName: dtpExecutor1 corePoolSize: 20 maximumPoolSize: 40 queueCapacity: 1000 ``` 在yml配置了哪些东西 1.globalExecutorProps:为了简化,线程池配置,dynamictp在globalExecutorProps里面可以配置全局的线程池配置。配置的优先级为**线程池配置 > 全局配置 > 字段默认值** 2.executors:自定义线程池配置,在里面初始化一个dtpExecutor1线程池 单元测试: ```java package com.example.demo; import org.dromara.dynamictp.core.executor.DtpExecutor; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; @SpringBootTest class DemoApplicationTests { @Resource private DtpExecutor dtpExecutor1; @Test void test() { System.out.println("以配置文件的方式创建的自定义线程池"); System.out.println(dtpExecutor1.getThreadPoolName()); System.out.println(dtpExecutor1.getCorePoolSize()); System.out.println(dtpExecutor1.getMaximumPoolSize()); System.out.println(dtpExecutor1.getQueueCapacity()); } } ``` 控制台输出 ```java 以配置文件的方式创建的自定义线程池 dtpExecutor1 20 40 1000 ``` 关于更多dynamic-tp可参考 [https://dynamictp.cn/guide/introduction/background.html](https://dynamictp.cn/guide/introduction/background.html) [https://gitee.com/dromara/dynamic-tp](https://gitee.com/dromara/dynamic-tp)
设计一个线程池
### 线程池是一个存储线程的一个容器,池内保存了之前建立过的线程来进行重复执行,减少开销(这倒是有点像字符串缓冲池) ### 要点:线程的管理,参数的暴露,任务存储结构的可配置,超负荷的任务的处理方式(丢弃,拒绝,异常)。 ### 这个线程池的是cpu密集还是io密集,改变任务的执行策略
怎么保证线程池中任务状态能正常推进?
<html> <head></head> <body> <div class="content ql-editor"> <p>目前遇到一个线程池的场景</p> <p>背景:通过@Bean注解声明了一个自定义的线程池,在项目中,跑任务方法会通过@Async注解指定该线程池进行异步执行。</p> <p>问题:在服务宕机、掉电、重启场景中,怎么保证未执行完的测试中的任务能正常推进?让其正常执行完,或直接转为 失败的状态?</p> <p>目前想到的通过定时任务扫表更新测试中状态,老表们有什么比较好的解决方法吗?</p> </div> </body> </html>
线程池参数策略
线程池 === 使用线程池用于维护一组线程,可以避免频繁的进行线程创建与销毁造成的浪费。需要使用线程的时候从线程池中取出就可以了。 案例 -- `public class ExecutorDemo { public static void main(String[] args) { int corePoolSize = 5; int maximumPoolSize = 10; long keepAliveTime = 1000; TimeUnit unit = TimeUnit.SECONDS; ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, new LinkedBlockingDeque<>()); for (int i = 0; i < 10; i++){ threadPoolExecutor.submit(() -> { System.out.println(Thread.currentThread().getName() + "正在执行"); }); } threadPoolExecutor.shutdown(); } }` 一般创建线程池都使用 ThreadPoolExecutor,可以更加灵活的控制参数,灵活的使用线程池。 参数说明 ---- * 1. 核心线程数:corePoolSize,线程池的核心线程数 * 2. 最大线程数:maximumPoolSize,线程池的最大线程数 * 3. 存活时间:keepAliveTime,超过核心线程数小于最大线程数的线程的存活时间 * 4. 时间单位:存活时间的时间单位。 * 5. 堵塞队列:blockedQueue,多余的任务排队 * 6. 拒绝策略:RejectedHandler 线程池维护一组核心线程池数的线程,当有超过该线程数的任务时,会被放在堵塞队列中等待,如果任务太多,堵塞队列也满了的话,会判断当前的线程数是否小于最大的线程数,是的话就会继续创建线程。 当执行完成后,大于核心线程数的线程空闲时间的达到存活时间后,会进行销毁。 当创建到等于最大线程池数的线程之后,如果还有任务的出现,并且把阻塞队列也满了,此时就会使用拒绝策略。 * 1. 核心线程数:线程池的核心线程数 I/O 密集型:使用对网络直接的传输,输入输出,对数据库操作等,这个操作可以设置较大的线程池数量。 CPU密集型:计算机应用的类型,为了可以充分的发挥CPU,线程池的数量一般为 CPU 的核的个数或倍数。 一般的情况下,假如CPU的核心数量为 N CPU 密集型可以设置为 N + 1 I/O 密集型可以设置为 N 的倍数. * 1. 最大线程数:线程池的最大线程数 搭配核心线程数,保持应用使用的线程数不会超出系统的上限。 具体的数量,还是根据实际的业务逻辑,以及测试所得。 * 1. 存活时间:keepAliveTime,超过核心线程数小于最大线程数的线程的存活时间 使用超过核心线程数的存放时间,一般短的任务可以设置较短的存活时间,长的任务设置较长的存放时间。 * 1. 时间单位:存活时间的时间单位。 这个搭配存活时间使用,一般有毫秒,秒,分钟。 * 1. 堵塞队列:多余的任务如何排队有界的阻塞队列一般使用 LinkedBlockQueue。无界的使用 sychronousQueue。 * 1. 拒绝策略:RejectedHander,当任务太多会触发拒绝策略,默认的为 AbortPolicy() ,抛出异常的策略。
线程池 基本原理
<html> <head></head> <body> <div class="content ql-editor"> <p>做个Java开发的小伙伴,或多或少的接触过线程池,但是为什么Java要提供线程池这个工具类呢?相信大家都听说过,线程对象比较重,重是什么意思?大家应该也接触过其他池化技术,比如数据库连接池,那这些池化技术和线程池的原理是否一样呢?我们先来明确一下,重到底是什么意思?一个普通的Java对象,它的创建过程无非就是加载类,在堆内存中分配空间,进行初始化,经过这三步Java对象就创建完成了,而线程对象的创建,除了需要经过这三步,还需要操作系统的配合,真正线程的创建是交给操作系统的,而操作系统创建线程就会用到其他资源(如果学过操作系统,至少应该知道操作系统会维护一个TCB),正是由于操作系统申请了其他资源,所以导致线程对象比普通的Java对象重。而对于这些比较重的对象,但是我们又需要频繁使用,一般我们会选择将它们缓存起来,用的时候申请并使用,不用的时候释放并让它回到缓存中。这就是池化技术,如果在程序中,需要<strong style="font-family: inherit; font-size: inherit;font-style;font-variant-ligatures;font-variant-caps;">频繁使用比较重的对象</strong>,那么一般都会利用池化技术提升性能。一般的池化技术基本上就是提前创建一堆对象,用的时候,拿去用,不用的时候,放回来。但是线程池无法这样设计,虽然从设计上,看上去可行,需要使用线程时,申请一个线程,使用完后,将这个线程放回池中。但是线程有个很致命的问题,<strong style="font-family: inherit; font-size: inherit;font-style;font-variant-ligatures;font-variant-caps;">线程创建之初,他所需要执行的流程就固定了,无法修改</strong>。所以一般的池化技术的设计思路就不可取了,于是Java对于线程池的设计,采用的<strong style="font-family: inherit; font-size: inherit;font-style;font-variant-ligatures;font-variant-caps;">生产者-消费者</strong>模型 生产者是使用线程池的我们,消费者就是线程池中的线程。</p> <p><img src="https://pic.code-nav.cn/planet_post_image/1628897468148121602/t3e0l6de.jpeg"></p> <p>使用线程池的我们,通过线程池提供的API,将我们需要执行的任务加入到阻塞队列中,而每个线程都执行着<strong>固定的流程</strong>,即从阻塞队列中取任务,调用它们的run()方法。这就是Java对于线程池的设计。</p> <p>不过在日常开发中,创建线程池的时候,推荐使用有界的阻塞队列,但是Java提供的Excutors.newxxxx()这些方法,传入的阻塞队列都是无界的即没有大小限制,很容易导致OOM(内存不够)</p> <p><br></p> </div> </body> </html>
@Async搭配线程池使用
<html> <head></head> <body> <div class="content ql-editor"> <p>1.创建一个线程池</p> <div class="ql-code-block-container"> <div class="ql-code-block"> package com.pjk.config; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> import com.sun.corba.se.spi.orbutil.threadpool.ThreadPool; </div> <div class="ql-code-block"> import org.springframework.context.annotation.Bean; </div> <div class="ql-code-block"> import org.springframework.context.annotation.Configuration; </div> <div class="ql-code-block"> import org.springframework.scheduling.annotation.EnableAsync; </div> <div class="ql-code-block"> import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> import java.util.concurrent.Executor; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> //线程池配置类 </div> <div class="ql-code-block"> @Configuration </div> <div class="ql-code-block"> @EnableAsync//开启spring对异步方法的支持 </div> <div class="ql-code-block"> public class ThreadPoolConfig { </div> <div class="ql-code-block"> @Bean(name = "taskExecutor") </div> <div class="ql-code-block"> public Executor taskExecutor() { </div> <div class="ql-code-block"> ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//创建线程池 </div> <div class="ql-code-block"> executor.setCorePoolSize(10); </div> <div class="ql-code-block"> executor.setMaxPoolSize(20); </div> <div class="ql-code-block"> executor.setQueueCapacity(30);//设定任务队列的个数 </div> <div class="ql-code-block"> executor.setThreadNamePrefix("taskExecutor");//设定线程池中的线程的名字前缀 线程名字将以此开头 </div> <div class="ql-code-block"> executor.initialize(); </div> <div class="ql-code-block"> return executor; </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> </div> </div> <p>2.创建一个异步方法类 在类中添加异步方法</p> <div class="ql-code-block-container"> <div class="ql-code-block"> package com.pjk.util; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> import org.springframework.scheduling.annotation.Async; </div> <div class="ql-code-block"> import org.springframework.stereotype.Component; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> import java.util.ArrayList; </div> <div class="ql-code-block"> import java.util.concurrent.CompletableFuture; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> @Component </div> <div class="ql-code-block"> public class AsyncMethod { </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> //测试异步方法 </div> <div class="ql-code-block"> @Async("taskExecutor") </div> <div class="ql-code-block"> public CompletableFuture<Integer> sum(ArrayList<Integer> integers ) throws InterruptedException { </div> <div class="ql-code-block"> CompletableFuture<Integer> completableFuture = new CompletableFuture<>(); </div> <div class="ql-code-block"> int sum=0; </div> <div class="ql-code-block"> for (Integer integer : integers) { </div> <div class="ql-code-block"> sum+=integer; </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> Thread.sleep(3000); </div> <div class="ql-code-block"> System.out.println("计算结果为:"+sum); </div> <div class="ql-code-block"> completableFuture.complete(sum); </div> <div class="ql-code-block"> return completableFuture; </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> </div> </div> <p>3.在你的类中 使用异步方法</p> <div class="ql-code-block-container"> <div class="ql-code-block"> package com.pjk; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> import com.pjk.util.AsyncMethod; </div> <div class="ql-code-block"> import org.junit.jupiter.api.Test; </div> <div class="ql-code-block"> import org.springframework.boot.test.context.SpringBootTest; </div> <div class="ql-code-block"> import org.springframework.scheduling.annotation.EnableAsync; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> import javax.annotation.Resource; </div> <div class="ql-code-block"> import java.util.ArrayList; </div> <div class="ql-code-block"> import java.util.concurrent.CompletableFuture; </div> <div class="ql-code-block"> import java.util.concurrent.ExecutionException; </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> @EnableAsync </div> <div class="ql-code-block"> @SpringBootTest </div> <div class="ql-code-block"> public class ThreadPoolTest { </div> <div class="ql-code-block"> @Resource </div> <div class="ql-code-block"> private AsyncMethod asyncMethod; </div> <div class="ql-code-block"> @Test </div> <div class="ql-code-block"> void testAsync() throws InterruptedException, ExecutionException { </div> <div class="ql-code-block"> ArrayList<Integer> integers = new ArrayList<>(1000000); </div> <div class="ql-code-block"> for (int i = 0; i < 1000000; i++) { </div> <div class="ql-code-block"> integers.add(i); </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> CompletableFuture<Integer> future = asyncMethod.sum(integers); </div> <div class="ql-code-block"> future.thenAccept(result->{ </div> <div class="ql-code-block"> System.out.println("测试异步结果:"+result); </div> <div class="ql-code-block"> }); </div> <div class="ql-code-block"> System.out.println("测试异步方法"); </div> <div class="ql-code-block"> Thread.sleep(5000); </div> <div class="ql-code-block"> System.out.println("测试异步结果"); </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> </div> <div class="ql-code-block"> } </div> <div class="ql-code-block"> </div> </div> <p><br></p> </div> </body> </html>
哥你好,我想问下,线程池的线程
哥你好,我想问下,线程池的线程数怎么确定,有什么方法或者工具吗?可以举个例子吗。
哥你好,我想问下,线程池的线程
哥你好,我想问下,线程池的线程数怎么确定,有什么方法或者工具吗?可以举个例子吗。
