记录Spring boot首次使用定时任务和多线程

       在工作过程中,遇到需要通过定时器进行数据更新,以及通过多线程加快远程服务器配置文件的更新速度的需求,对于一个刚工作的新人也是一个不小的挑战,由于之前对于这些知识只是简单的使用,同时也没有通过spring boot进行实现,特此记录便于自己查阅。

       关于定时器的实现,在spring boot中有专门的实现,通过注解开发,大大减轻了工作量。spring boot中提供了两种调度方式。第一种是串行的方式,使用也较简单。首先在spring boot的程序入口通过@EnableScheduling开启总开关。


@SpringBootApplication
@EnableScheduling
public class DemoApplication {
 
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

        之后在需要定时执行的方法上添加@Scheduled注解即可,注意方法所在的类要被spring boot可以扫描到,也就是加上类似@Compont、@Service等注解如下图:

@Scheduled(cron = "0/2 * * * * *")
public void timer(){

   ........

}

        其中,cron中设置的字符串是cron表达式,用来设置改方法执行的时间间隔,程序启动后便会定时执行。读者需要的话可以自学一下cron表达式,网上也有很多在线生成cron表达式的工具、网页等。cron表达式,有专门的语法,而且感觉有点绕人,不过简单来说,大家记住一些常用的用法即可,特殊的语法可以单独去查。cron一共有7位,但是最后一位是年,可以留空,所以我们可以写6位:

  1. 第一位,表示秒,取值0-59
  2. 第二位,表示分,取值0-59
  3. 第三位,表示小时,取值0-23
  4. 第四位,日期天/日,取值1-31
  5. 第五位,日期月份,取值1-12
  6. 第六位,星期,取值1-7,星期一,星期二...,不是第1周,第二周的意思 ,注意:1表示星期天,2表示星期一
  7. 第7为,年份,可以留空,取值1970-2099

        定时器的第二种实现方式为并行的方式。当定时任务很多的时候,为了提高任务执行效率,可以采用并行方式执行定时任务,任务之间互不影响, 通过自定义类实现SchedulingConfigurer接口就可以,重写configureTasks方法,为了让spring boot可扫描到该类,同样需要在类上定义注解,具体执行周期同样通过cron表达式来定义,具体如下:

@Component
public class ScheduleTask implements SchedulingConfigurer{
    
    @Autowired
    private Service serviceImpl;
    
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        // TODO Auto-generated method stub
        taskRegistrar.addTriggerTask(new Runnable() {
            
            @Override
            public void run() {
                 serviceImpl.save();           
            }
        }, new Trigger() {
            
            @SuppressWarnings("boxing")
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                    String cron="0/3 * * * * *";
                    CronTrigger trigger = new CronTrigger(cron); // 定时任务触发,可修改定时任务的执行周期
                    Date nextExecDate = trigger.nextExecutionTime(triggerContext);
                    return nextExecDate;
                }                           
            }
        });
    }

}

 以上为spring boot定时器的实现方法,我采用的第二种方法。

         在spring boot中实现多线程的使用,我采用的是下述方法,对于多线程的使用,后面我还需要多多学习。

         首先编写配置类AsyncConfig,

@SpringBootConfiguration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer{

    @Override
    public Executor getAsyncExecutor() {

    // ThredPoolTaskExcutor的处理流程
    // 当池子大小小于corePoolSize,就新建线程,并处理请求
    // 当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去workQueue中取任务并处理
    // 当workQueue放不下任务时,就新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理
    // 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁

        ThreadPoolTaskExecutor threadPoolTaskExecutor=new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(5);//核心池大小
        threadPoolTaskExecutor.setMaxPoolSize(10);//最大池大小
        threadPoolTaskExecutor.setQueueCapacity(25);
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

        // TODO Auto-generated method stub
        return null;
    }

}

        在配置类上通过@SpringBootConfiguration表明是一个配置类,通过@EnableAsync开启多线程的开关。然后编写自己的线程类执行具体线程的代码。在类上通过@service注解使得spring boot可以扫描到该类,进而进行管理,在方法上通过@Async注解定义一个线程,只要通过自动注入该类的实例,调用这个方法就会开启一个线程去执行具体定义的任务。

@Service
public class PersonalThread {

    @SuppressWarnings("boxing")
    @Async
    public void personalRun() {

        //线程执行的代码
    }

}

       通过PersonalThread类的对象调用响应的方法来开启线程,每次调用开启一个线程。

personalThread.personalRun();

 

        在具体操作的过程中,还遇到了一个问题,由于开启定时器与多线程进行的操作都涉及到对数据库的更新操作,这样自然而然就会出现多线程中经常遇到的数据更新不一致问题,更新结果经常出问题,于是刚开始我采取在进行保存操作时将定时器暂停,保存之后在开启定时器的方法,但是这种方法貌似定时器在执行完当前周期才会停,没有立即停掉,这样会增加保存操作的延时,而且貌似数据更新还是存在问题......,于是目前我采用单例定义了一个对象,通过加锁的方式保证数据更新的正确性,但是还是存在问题,这样处理的结果导致更新操作由于需要获得锁而有不确定的延时,但是好歹数据保存结果执行正确,读者有什么好方法可以告诉我哈,本人菜鸟一个,求指教~

        程序之路漫漫,吾将上下而求索

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值