- 项目中为了更好的控制线程的使用,我们可以自定义我们自己的线程池,使用方式@Async(“myThreadPool”)
废话太多,直接上代码:
@Scheduled(fixedRate = 100010,initialDelay = 100020)
@Async(“myThreadPoolTaskExecutor”)
//@Async
public void scheduledTest02(){
System.out.println(Thread.currentThread().getName()+“—>xxxxx—>”+Thread.currentThread().getId());
}
//自定义线程池
@Bean(name = “myThreadPoolTaskExecutor”)
public TaskExecutor getMyThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(20);
taskExecutor.setMaxPoolSize(200);
taskExecutor.setQueueCapacity(25);
taskExecutor.setKeepAliveSeconds(200);
taskExecutor.setThreadNamePrefix(“Haina-ThreadPool-”);
// 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//调度器shutdown被调用时等待当前被调度的任务完成
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
//等待时长
taskExecutor.setAwaitTerminationSeconds(60);
taskExecutor.initialize();
return taskExecutor;
}
线程池的使用心得
-
java中提供了ThreadPoolExecutor和ScheduledThreadPoolExecutor,对应与spring中的ThreadPoolTaskExecutor和ThreadPoolTaskScheduler,但是在原有的基础上增加了新的特性,在spring环境下更容易使用和控制。
-
使用自定义的线程池能够避免一些默认线程池造成的内存溢出、阻塞等等问题,更贴合自己的服务特性
-
使用自定义的线程池便于对项目中线程的管理、维护以及监控。
-
即便在非spring环境下也不要使用java默认提供的那几种线程池,坑很多,阿里代码规约不说了吗,得相信大厂!!!
三、动态定时任务的实现
===========
问题:
使用@Scheduled注解来完成设置定时任务,但是有时候我们往往需要对周期性的时间的设置会做一些改变,或者要动态的启停一个定时任务,那么这个时候使用此注解就不太方便了,原因在于这个注解中配置的cron表达式必须是常量,那么当我们修改定时参数的时候,就需要停止服务,重新部署。
解决办法:
方式一:实现SchedulingConfigurer接口,重写configureTasks方法,重新制定Trigger,核心方法就是addTriggerTask(Runnable task, Trigger trigger) ,不过需要注意的是,此种方式修改了配置值后,需要在下一次调度结束后,才会更新调度器,并不会在修改配置值时实时更新,实时更新需要在修改配置值时额外增加相关逻辑处理。
@Configuration
public class ScheduledConfig implements SchedulingConfigurer {
@Autowired
private TaskScheduler myThreadPoolTaskScheduler;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
//scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
scheduledTaskRegistrar.setTaskScheduler(myThreadPoolTaskScheduler);
//可以实现动态调整定时任务的执行频率
scheduledTaskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> System.out.println(“cccccccccccccccc—>” + Thread.currentThread().getId()),
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1 从数据库动态获取执行周期
String cron = "0/2 * * * * ? ";
//2.2 合法性校验.
// if (StringUtils.isEmpty(cron)) {
// // Omitted Code …
// }
//2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
方式二:使用threadPoolTaskScheduler类可实现动态添加删除功能,当然也可实现执行频率的调整
首先,我们要认识下这个调度类,它其实是对java中ScheduledThreadPoolExecutor的一个封装改进后的产物,主要改进有以下几点:
-
提供默认配置,因为是ScheduledThreadPoolExecutor,所以只有poolSize这一个默认参数。
-
支持自定义任务,通过传入Trigger参数。
-
对任务出错处理进行优化,如果是重复性的任务,不抛出异常,通过日志记录下来,不影响下次运行,如果是只执行一次的任务,将异常往上抛。
顺便说下ThreadPoolTaskExecutor相对于ThreadPoolExecutor的改进点:
-
提供默认配置,原生的ThreadPoolExecutor的除了ThreadFactory和RejectedExecutionHandler其他没有默认配置
-
实现AsyncListenableTaskExecutor接口,支持对FutureTask添加success和fail的回调,任务成功或失败的时候回执行对应回调方法。
-
因为是spring的工具类,所以抛出的RejectedExecutionException也会被转换为spring框架的TaskRejectedException异常(这个无所谓)
-
提供默认ThreadFactory实现,直接通过参数重载配置
扯了这么多,还是直接上代码:
@Component
public class DynamicTimedTask {
private static final Logger logger = LoggerFactory.getLogger(DynamicTimedTask.class);
//利用创建好的调度类统一管理
//@Autowired
//@Qualifier(“myThreadPoolTaskScheduler”)
//private ThreadPoolTaskScheduler myThreadPoolTaskScheduler;
//接受任务的返回结果
private ScheduledFuture<?> future;
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
//实例化一个线程池任务调度类,可以使用自定义的ThreadPoolTaskScheduler
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
return new ThreadPoolTaskScheduler();
}
/**
-
启动定时任务
-
@return
*/
public boolean startCron() {
boolean flag = false;
//从数据库动态获取执行周期
String cron = "0/2 * * * * ? ";
future = threadPoolTaskScheduler.schedule(new CheckModelFile(),cron);
if (future!=null){
flag = true;
logger.info(“定时check训练模型文件,任务启动成功!!!”);
}else {
logger.info(“定时check训练模型文件,任务启动失败!!!”);
}
return flag;
}
/**
-
停止定时任务
-
@return
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
看完美团、字节、腾讯这三家的面试问题,是不是感觉问的特别多,可能咱们又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。
开篇有提及我可是足足背下了1000道题目,多少还是有点用的呢,我看了下,上面这些问题大部分都能从我背的题里找到的,所以今天给大家分享一下互联网工程师必备的面试1000题。
注意不论是我说的互联网面试1000题,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友
互联网工程师必备的面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
转存中…(img-wySQEgMX-1711822998661)]
互联网工程师必备的面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
[外链图片转存中…(img-FZeNfrBU-1711822998661)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!