项目-25-初始任务执行和调度

初始任务执行和调度

我们需要定时计算各帖子的分数,清除临时文件等,这就需要任务调度的组件。

JDK线程池

  • ExecutorService:普通的线程池
  • ScheduledExecutorService:可以执行定时任务(分布式环境可能出问题)

Spring 线程池

  • ThreadPoolTaskExecutor:普通的线程池
  • ThreadPoolTaskScheduler:可以执行定时任务(分布式环境可能出问题)

分布式定时任务

  • Spring Quartz(将数据存储到数据库,分布式时可以共享数据)
    • 核心调度接口Scheduler
    • 定义任务的接口Job的execute方法
    • Jobdetail接口来配置Job的名字、组等
    • Trigger接口配置Job的什么时候运行、运行频率
    • QuartzConfig:配置 -> 数据库 -> 调用
  • FactoryBean可简化Bean的实例化过程:
    1. 通过FactoryBean封装Bean的实例化过程
    2. 将FactoryBean装配到Spring容器里
    3. 将FactoryBean注入给其他的Bean.
    4. 该Bean得到的是FactoryBean所管理的对象实例.

如果我们采用JDK或者Spring的Scheduler执行定时任务在分布式环境可能出问题。因为JDK或者Spring的Scheduler设置的执行参数是保存在内存中,服务器之间不共享内存,当多个Scheduler操作时,就会产生问题。如果通过Quartz,就可以解决。Quartz的配置参数是保存在数据库中。

测试:

Spring需要进行配置:

#TaskExecutionProperties
#核心线程数量
spring.task.execution.pool.core-size=5
#最大线程数量
spring.task.execution.pool.max-size=15
#工作队列容量
spring.task.execution.pool.queue-capacity=100

#TaskSchedulingProperties
spring.task.scheduling.pool.size=5

配置类:

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration //表示配置类
@EnableScheduling //开始spring的定时线程池
@EnableAsync //开启注解spring的线程池 -->@Async @Scheduled(initialDelay = 10000, fixedRate = 1000)
public class ThreadPoolConfig {
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ThreadPoolTests {

    // logger
    private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTests.class);
    // 1. JDK普通的线程池
    private ExecutorService executorService = Executors.newFixedThreadPool(5);
    // 2. JDK可执行定时任务的线程池
    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
    // 3. spring的线程池
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;
    @Autowired
    private AlphaService alphaService;

    //封装sleep方法
    private void sleep(long m){
        try {
            Thread.sleep(m);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testExecutorService(){
        Runnable task = new Runnable() {
            @Override
            public void run() {
                logger.debug("JDK普通的线程池");
            }
        };
        for (int i = 0; i < 10; i++) {
            executorService.submit(task);
        }
        sleep(10000);
    }

    @Test
    public void testScheduledExecutorService(){
        Runnable task = new Runnable() {
            @Override
            public void run() {
                logger.debug("JDK可执行定时任务的线程池");
            }
        };
        /**
         * command:执行线程
         * initialDelay:初始化延时
         * period:两次开始执行最小间隔时间
         * unit:计时单位
         */
        scheduledExecutorService.scheduleAtFixedRate(task, 10000, 1000, TimeUnit.MILLISECONDS);
        sleep(30000);
    }

    //spring普通线程池
    @Test
    public void testThreadPoolTaskExecutor(){
        Runnable task = new Runnable() {
            @Override
            public void run() {
                logger.debug("spring普通线程池");
            }
        };
        for (int i = 0; i < 10; i++) {
            taskExecutor.submit(task);
        }
        sleep(10000);
    }

    //spring定时线程池
    @Test
    public void testThreadPoolTaskScheduler(){
        Runnable task = new Runnable() {
            @Override
            public void run() {
                logger.debug("spring定时线程池");
            }
        };
        //延迟一秒执行
        Date startTime = new Date(System.currentTimeMillis() + 10000);
        taskScheduler.scheduleAtFixedRate(task, startTime, 10000);
        sleep(10000);
    }

    //简化版 spring普通
    @Test
    public void testEasyTask(){
        for (int i = 0; i < 10; i++) {
            alphaService.executel();
        }
        sleep(10000);
    }

    //简化版 spring定时线程池
    @Test
    public void testEasyTask2(){
        sleep(10000);
    }
  
    /*    
    AlphaService中添加的方法
    // 让该方法在多线程环境下,被异步的调用.
    @Async
    public void execute1() {
        logger.debug("execute1");
    }
	
    @Scheduled(initialDelay = 10000, fixedRate = 1000)
    public void execute2() {
        logger.debug("execute2");
    }
  	*/
}

Quartz:

因为Quartz是基于数据库的,首先初始化tables_mysql_innodb.sql

  • qrtz_job_detail:对任务(job)描述的表
  • qrtz_simple_triggers:触发器有关的简单配置
  • qrtz_triggers:触发器有关的配置
  • qrtz_scheduler_state:定时器的有关内容
  • qrtz_locks:锁的信息

Quartz的基本组成部分:

  • 调度器:Scheduler:核心调度接口
  • 任务:时间Job接口,声明任务。通过JobDetail配置Job的详细参数
  • 触发器:Trigger,包括SimpleTrigger和CronTrigger,配置Job运行时的参数

测试:

1.导包

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>

2.实现job接口

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

//例子
public class AlphaJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println(Thread.currentThread().getName()+"quartzJob");
    }
}

3.编写配置类

import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

//QuartzConfig为Quartz的配置类
//作用:当在配置文件中配置Quartz信息后,在第一次调用时,将配置信息写回数据库中,之后就直接读取数据库中的信息
@Configuration
public class QuartzConfig {

    //FactoryBean作用:简化bean的实例化过程
    //1.通过FactoryBean封装Bean的实例化过程
    //2.将FactoryBean装配到spring容器中
    //3.将FactoryBean注入给其他的bean
    //4.其他的bean即可获得FactoryBean所管理的对象实例


    // 1. 配置jobDetail
    @Bean
    public JobDetailFactoryBean alphaJobDetail(){
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(AlphaJob.class);	//声明要配置的job类
        factoryBean.setName("alphaJob");	//声明job的名称
        factoryBean.setGroup("alphaJobGroup");	//声明job的分组
        factoryBean.setDurability(true);	//job是否长久的存在,true为长久存在
        factoryBean.setRequestsRecovery(true);	//job是否可被恢复
        return factoryBean;
    }
    // 2. 配置trigger
    //   SimpleTriggerFactoryBean:简单的定时;
    //   CronTriggerFactoryBean:可实现复杂的定时,如每月的1号进行清除
    @Bean //alphaTrigger即得到了JobDetail
    public SimpleTriggerFactoryBean alphaTrigger(JobDetail alphaJobDetail){
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(alphaJobDetail); 	//确定JobDetail
        factoryBean.setName("alphaTrigger"); 	//Trigger的名称
        factoryBean.setGroup("alphaTriggerGroup"); 	//Trigger的分组
        factoryBean.setRepeatInterval(3000);	//时间间隔3秒
        factoryBean.setJobDataMap(new JobDataMap());	 //保存数据的类型
        return factoryBean;
    }
}

4.对Quartz进行配置

注:如果我们没有对Quartz进行配置,就会利用Quartz的默认配置进行运行,并不会将配置信息写回数据库中。

# QuartzProperties
spring.quartz.job-store-type=jdbc  //存储方式 
spring.quartz.scheduler-name=communityScheduler //调度器的名称
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO //自动生成调度器的id
spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX //存储需要的类
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate //驱动
spring.quartz.properties.org.quartz.jobStore.isClustered=true //采用集群的方式
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool //所用线程池
spring.quartz.properties.org.quartz.threadPool.threadCount=5 //线程池的数量
//删除Quartz数据库中的job
import org.junit.Test;
import org.junit.runner.RunWith;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class QuartzTest {

    //删除Quartz数据库中的job
    @Autowired
    private Scheduler scheduler;

    @Test
    public void deleteJob(){
        try {
            // JobKey(job的名称, job的组名)
            boolean b = scheduler.deleteJob(new JobKey("alphaJob", "alphaJobGroup"));
            System.out.println(b);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值