Springboot自带线程池怎么实现
一: ThreadPoolTaskExecuto
1 ThreadPoolTaskExecutor线程池:
ThreadPoolTaskExecutor是Spring基于java本身的线程池ThreadPoolExecutor做的二次封装,主要目的还是为了更加方便的在spring框架体系中使用线程池, 是Spring中默认的线程池
2 使用ThreadPoolTaskExecutor注入bean到ioc中
配置文件形式,Spring会自动配置
## 默认线程池配置,ThreadPoolTaskExecutor # 核心线程数spring.task.execution.pool.core-size=8 # 最大线程数spring.task.execution.pool.max-size=16# 空闲线程存活时间spring.task.execution.pool.keep-alive=60s# 是否允许核心线程超时spring.task.execution.pool.allow-core-thread-timeout=true# 线程队列数量spring.task.execution.pool.queue-capacity=100# 线程关闭等待spring.task.execution.shutdown.await-termination=falsespring.task.execution.shutdown.await-termination-period=# 线程名称前缀spring.task.execution.thread-name-prefix=demo_Thread
配置形式:
import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import java.util.concurrent.Executor;import java.util.concurrent.ScheduledFuture;//@Configurationpublic class ThreadConfig { @Value("${task.maxPoolSize}") private int maxPoolSize; //todo 其他的相关配置都可以通过配置文件中注入 @Bean("ThreadPoolTaskExecutor") public Executor myAsync() { final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setMaxPoolSize(maxPoolSize); //todo 其他参数设置 //初始化 executor.initialize(); return executor; }}
3 创建线程后全部从ioc中获取线程池子
4 线程池处理流程:
(1) 查看核心线程池是否已满,不满就创建一条线程执行任务,核心线程数量已满就查看任务队列是否已满不满就将线程存储在任务队列中任务队列已满,就查看最大线程数量,不满就创建线程执行任务,已满就按照拒绝策略执行
(2) 拒绝策略:
-
CallerRunsPolicy():原来的线程执行
-
AbortPolicy():直接抛出异常
-
DiscardPolicy():直接丢弃
-
DiscardOldestPolicy():丢弃队列中最老的任
二: ThreadPoolTaskScheduler
1 ThreadPoolTaskScheduler 定时调度任务线程池,处理异步任务
2 使用方式: 注入 ThreadPoolTaskScheduler的bean
(1) 配置文件形式:..
(2) 配置类形式:
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import java.util.concurrent.ScheduledFuture;@Configurationpublic class ThreadPoolTaskSchedulerConfig { @Bean public ThreadPoolTaskScheduler threadPoolTaskScheduler() { final ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); //设置等待任务在关机时l候完成 threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true); //设置等待时间为60s threadPoolTaskScheduler.setAwaitTerminationSeconds(60); return threadPoolTaskScheduler; }}
3 使用ThreadPoolTaskScheduler定时任务
做普通线程池使用:
-
submit(callable),需要执行结果
-
submit(runnable),不需要执行结果
(1) 定时任务
添加任务内容Runnable,设置执行周期Trigger/Date,Trigger表达式百度即可
schedule(Runnable task,Trigger) schedule(Runnable task,Date)
(2) 指定间隔时间执行一次任务,时间间隔是前一次任务完成到下一次任务开始,单位毫秒
scheduleWithFixedDelay(Runnable task,long delay)
(3) 固定频率执行任务,在任务开始后间隔一段时间执行新的任务,如果上次任务么执行完成,则等待上次任务执行完成后执行下次任务
scheduleAtFixedRate(Runnable task,long delay)
(4) 定时任务取消:
设置定时任务存储的集合,定时任务执行的结果为ScheduledFuture<?>,将该对象存储到集合,通过在集合中获取ScheduledFuture<?>对象.cancel(true)取消定时任务
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import org.springframework.scheduling.support.CronTrigger;import org.springframework.stereotype.Service;import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.*;@Servicepublic class SchedulerService { @Autowired ThreadPoolTaskScheduler scheduler; /** * 常规线程池使用 */ public void tesScheduler1() throws ExecutionException, InterruptedException { //无返回值 final Future<?> demo_scheduler1 = scheduler.submit(new Runnable() { @Override public void run() { System.out.println("demo runnable scheduler"); } }); //无返回值 final Future<?> demo_scheduler2 = scheduler.submit(new Callable<Object>() { @Override public Object call() throws Exception { System.out.println("demo callable scheduler"); return "callable"; } }); System.out.println("result:" + demo_scheduler2.get()); } /** * 定时任务 */ public void tesScheduler2() throws ParseException { //CronTrigger表达式百度即可 scheduler.schedule(() -> { System.out.println("定时任务"); }, new CronTrigger("0/1****?")); //创建指定时间的日期 final Date date = new Date(2023, 3, 26, 21, 35); final DateFormat format = new SimpleDateFormat(); final Date parse = format.parse("2023-03-26-21-26"); scheduler.schedule(() -> { System.out.println(new Date()); }, parse); } /** * 指定时间间隔执行任务,上次任务结束到下次任务开始的时间间隔 */ public void tesScheduler3() { scheduler.scheduleWithFixedDelay(() -> { //todo }, 300L); } /** * 固定频率执行任务,在固定一段时间后便会执行下次任务, * 如果时间到了上次任务还没执行完毕则等待, * 直到上一次任务执行完毕后立马执行下次任务 */ public void tesScheduler4() { scheduler.scheduleAtFixedRate(new FutureTask<String>(new Callable<String>() { @Override public String call() throws Exception { return null; } }), 200); } //取消定时任务队列 public static ConcurrentMap<String, ScheduledFuture> map = new ConcurrentHashMap<>(); public void startTask(String k1) { map.compute(k1, (k, v) -> { if (map.containsKey(k)) return v; map.put(k, v); return v; }); }}
三 @Scheduled实现定时任务,注解开启定时任务
1 使用@EnableScheduled开启支持
2 @Scheduled标注方法
(1)@Scheduled(fixedDelay=5000)延迟执行,5s后执行
(2)@Scheduled(fixedRate=5000)定时执行,每隔五秒就进行执行
(3)@Scheduled(corn="002**?") 自定义执行,corn表达式百度,常用这种执行方式,corn="002**?"每天凌晨两点开始执行定时任务
3 注意@Scheduled开启的任务是单线程的,容易阻塞
(1) 在ioc中注入ThreadPoolTaskScheduler,则Scheduled就使用ThreadPoolTaskScheduler线程池,可以解决单线程阻塞问题
(2) @Scheduled和@Async注解开启定时任务,在@Async("pool")中指定线程池,若是没有指定线程池会使用Spring的SimpleAsyncTaskExecutor线程池,这个线程池每次都会增加一个线程去执行任务,效率低下
四:Spring中的异步任务
1 @EnableAsync开启异步支持
2 @Async开启异步任务,指定线程池
注意:@Scheduled和@Async注解开启定时任务,在@Async("pool")中指定线程池,若是没有指定线程池会使用Spring的SimpleAsyncTaskExecutor线程池,这个线程池每次都会增加一个线程去执行任务,效率低下但是@Async单独开启异步任务,则使用的是默认的线程池,建议根据需求自定义线程池
注意:@Async的返回值只能为void或Future, 调用方和@Async不能在一个类中,否则不走aop;
import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class AsyncService { @Async public void showThreadName1() { //默认线程池 System.out.println(Thread.currentThread().getName()); } @Async("myPool")//指定线程池 public void showThreadName2() { System.out.println(Thread.currentThread().getName()); }}
五:献上一颗自java自定义线程池:
@Bean("myPool") public Executor executor(){ return new ThreadPoolExecutor(// 自定义一个线程池 1, // coreSize 2, // maxSize 60, // 60s TimeUnit.SECONDS, new ArrayBlockingQueue<>(3) // 有界队列,容量是3个 , Executors.defaultThreadFactory() , new ThreadPoolExecutor.AbortPolicy()); }
java自带的线程池,缓存,固定数量的,单线程的,定时的,,,,六七种,后面续上