springTask阻塞问题

问题前提:
1.springTask执行多个定时任务单线程执行(执行完任务A才能执行任务B),导致周期延迟.
2.如果一个定时任务周期是2s,业务执行需要5s,下一次定时周期会阻塞到5s.导致周期延迟

1.创建springBoot项目

2.启动类加入注解@EnableScheduling

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

3.创建定时任务

@Component
public class TestTask {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    // 定义每过3秒执行任务
    @Scheduled(fixedRate = 3000)
    public void reportCurrentTime() {
           System.out.println("任务A:现在时间:" + dateFormat.format(new Date())+Thread.currentThread().getName());
    }

    // 定义每过3秒执行任务
    @Scheduled(fixedRate = 3000)
    public void reportCurrentTime2() {
        System.out.println("任务B:现在时间:" + dateFormat.format(new Date())+Thread.currentThread().getName());
    }
}

执行结果:

任务B:现在时间:15:07:47scheduling-1
任务A:现在时间:15:07:47scheduling-1
任务B:现在时间:15:07:50scheduling-1
任务A:现在时间:15:07:50scheduling-1
任务B:现在时间:15:07:53scheduling-1
任务A:现在时间:15:07:53scheduling-1
任务B:现在时间:15:07:56scheduling-1
任务A:现在时间:15:07:56scheduling-1 

4.多个定时任务出现线程阻塞的问题

1.之前有没有发现一个问题(任务A.B使用的是同一线程)?
现在我们修改代码

@Component
public class TestTask {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    // 定义每过3秒执行任务
    @Scheduled(fixedRate = 3000)
    public void reportCurrentTime() {
           System.out.println("任务A:现在时间:" + dateFormat.format(new Date())+Thread.currentThread().getName());
            while (true){
            try {
                //业务执行花费10s
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            break;
        }
    }
   

    // 定义每过3秒执行任务
    @Scheduled(fixedRate = 3000)
    public void reportCurrentTime2() {
        System.out.println("任务B:现在时间:" + dateFormat.format(new Date())+Thread.currentThread().getName());
    }
}

执行结果:

任务B:现在时间:15:13:42scheduling-1
任务A:现在时间:15:13:42scheduling-1
任务B:现在时间:15:13:52scheduling-1
任务A:现在时间:15:13:52scheduling-1
任务B:现在时间:15:14:02scheduling-1
任务A:现在时间:15:14:02scheduling-1
任务B:现在时间:15:14:12scheduling-1
任务A:现在时间:15:14:12scheduling-1
任务B:现在时间:15:14:22scheduling-1
任务A:现在时间:15:14:22scheduling-1

线程执行流程: 任务B(阻塞低于1秒)→任务A(阻塞10s)→任务B(低于一秒)→任务A(阻塞10s)
任务A间隔10秒执行(设置周期3s)
任务B间隔10秒执行(设置周期3s)

任务A阻塞会导致B任务出现延迟


解决方法:
加入配置:

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer, AsyncConfigurer {
 
	/** 异步处理 */
	@Override
	public void configureTasks(ScheduledTaskRegistrar taskRegistrar){
		TaskScheduler taskScheduler = taskScheduler();
		taskRegistrar.setTaskScheduler(taskScheduler);
	}
 
	/** 定时任务多线程处理 */
	@Bean(destroyMethod = "shutdown")
	public ThreadPoolTaskScheduler taskScheduler(){
		ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
		scheduler.setPoolSize(50);
		scheduler.setThreadNamePrefix("task-");
		scheduler.setAwaitTerminationSeconds(1);
        scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		scheduler.setWaitForTasksToCompleteOnShutdown(true);
		return scheduler;
	}
 
	/** 异步处理 */
	@Override
	public Executor getAsyncExecutor(){
		Executor executor = taskScheduler();
		return executor;
	}
 
	/** 异步处理 异常 */
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(){
		return new SimpleAsyncUncaughtExceptionHandler();
	}
}

执行结果:

任务A:现在时间:15:23:57task-3
任务B:现在时间:15:23:59task-1
任务B:现在时间:15:24:02task-2
任务B:现在时间:15:24:05task-6
任务A:现在时间:15:24:07task-7
任务B:现在时间:15:24:08task-4
任务B:现在时间:15:24:11task-1
任务B:现在时间:15:24:14task-8

任务B间隔3秒执行 (设置周期3s)
任务A间隔10秒执行 (设置周期3s)

我们暂时解决了多个定时任务之间发生阻塞的问题.

5.单个定时任务如何防止阻塞

1.启动类加入注解支持@EnableAsync
2.在定时任务方法上加入注解@Async

@SpringBootApplication
@EnableScheduling
@EnableAsync
public class application {
    public static void main(String[] args) {
        SpringApplication.run(application.class,args);
    }
}
@Component
public class TestTask {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    // 定义每过3秒执行任务
    @Async
    @Scheduled(fixedRate = 3000)
    public void reportCurrentTime() {
           System.out.println("任务A:现在时间:" + dateFormat.format(new Date())+Thread.currentThread().getName());
            while (true){
            try {
                //业务执行花费10s
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            break;
        }
    }
   

    // 定义每过3秒执行任务
    @Async
    @Scheduled(fixedRate = 3000)
    public void reportCurrentTime2() {
        System.out.println("任务B:现在时间:" + dateFormat.format(new Date())+Thread.currentThread().getName());
        while (true){
            try {
                //业务执行花费10s
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            break;
        }
    }
}

执行结果:

任务A:现在时间:15:37:03task-5
任务B:现在时间:15:37:03task-6
任务B:现在时间:15:37:06task-4
任务A:现在时间:15:37:06task-9
任务A:现在时间:15:37:09task-15
任务B:现在时间:15:37:09task-16
任务A:现在时间:15:37:12task-8
任务B:现在时间:15:37:12task-3

任务A间隔3秒执行(设置周期3s)
任务B间隔3秒执行(设置周期3s)
问题解决!
注:ScheduleConfig 配置类中
scheduler.setPoolSize(50); //设置可使用的线程大小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值