ホームページ  >  記事  >  Java  >  Java Springでスケジュールされたタスクを実装する方法

Java Springでスケジュールされたタスクを実装する方法

PHPz
PHPz転載
2023-05-24 13:28:231242ブラウズ

java はスケジュールされたタスクを実装します

Jdk に付属のライブラリでは、スケジュールされたタスクを実装する 2 つの方法があります。1 つは Timer、もう 1 つは ScheduledThreadPoolExecutor

Timer TimerTask

Timer を作成すると、TimerTask タスクのスケジュールに使用できるスレッドが作成されます

Java Springでスケジュールされたタスクを実装する方法

Timer には 4 つの構築メソッドがあり、Timer スレッドの名前と、それをデーモン スレッドとして設定するかどうかを指定できます。デフォルト名は Timer-number で、デフォルトではデーモン スレッドではありません。

主なメソッドは 3 つあります:

cancel(): タスクのスケジュールを終了し、現在スケジュールされているすべてのタスクをキャンセルします。実行中のタスクは影響を受けません

purge(): キャンセルされたすべてのタスクをタスク キューから削除します。

#schedule: タスクのスケジュールを開始し、いくつかのオーバーロードされたメソッドを提供します。 :

schedule(TimerTask タスク、長い遅延) 実行を遅延します。つまり、deflaytasktask## の後に 1 回実行されます。

#schedule(TimerTask タスク, Date time)`指定された時刻に実行し、`time` 時刻に `タスクを 1 回実行します
#schedule(TimerTask task, long late, long period)`遅延サイクル実行、` `task

schedule( TimerTask タスク、Date firstTime、long period)` は、指定された時間 `firstTime` の後に定期的に実行され、指定された時間 `firstTime` に達した後は `period` ミリ秒ごとに 1 回実行されます。 ##

public class TimerTest {
    public static void main(String[] args) {
        Timer timer = new Timer("aa");
        Task task = new Task();
        timer.schedule(task,new Date(),1000);
    }
}
class Task extends TimerTask{
    @Override
    public void run() {
        System.out.println(new Date());
    }
}


出力:

Thu Jul 07 14:50:02 CST 2022
Thu Jul 07 14:50:03 CST 2022

Thu Jul 07 14:50:04 CST 2022

Thu Jul 07 14:50:05 CST 2022
…………



欠点

タイマーはシングルスレッドであり、例外をスローしません。スケジュールされたタスクで例外が発生すると、スレッド全体が停止し、スケジュールされたタスクが終了します。

ScheduledThreadPoolExecutor

Timer

には欠陥があるため、

Timer

を使用することはお勧めできません。

ScheduledThreadPoolExecutor# を使用することをお勧めします。 ##。

ScheduledThreadPoolExecutor は、Timer の代替品です。JDK1.5 で導入され、ThreadPoolExecutor

を継承しています。これは、に基づいたスケジュールされたタスク クラスです。スレッドプール設計です。

主なスケジューリング方法:

schedule

スケジューリングを 1 回だけ実行 (タスク、遅延時間、遅延時間単位)

Java Springでスケジュールされたタスクを実装する方法scheduleAtFixedRate

固定頻度でスケジューリングします。実行時間が長すぎると、次のスケジューリングが遅れます(タスク、最初の実行の遅延時間、期間、時間単位)

scheduleWithFixedDelay

遅延スケジューリング。タスクの実行後、次のタスクを実行するために遅延時間が追加されます (タスク、最初の実行の遅延時間、インターバル時間、時間単位)

Example

public class TimerTest {
    public static void main(String[] args) throws Exception{
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.scheduleAtFixedRate(
                () -> System.out.println(new Date()),
                1,3, TimeUnit.SECONDS);
    }
}

Spring スケジュールされたタスク

Spring スケジュールされたタスクは、主に @Scheduled

アノテーション、

corn、fixedDelay、fixedDelayString、fixedRate、fixedRateString

によって実装されます。 5 つのパラメータは必須です。そのうちの 1 つを指定し、2 つまたは 3 つを渡すと例外がスローされます。

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
	String CRON_DISABLED = ScheduledTaskRegistrar.CRON_DISABLED;
    // cron表达式
	String cron() default "";
    // 时区
	String zone() default "";
    // 从上一次调用结束到下一次调用之间的固定时间
	long fixedDelay() default -1;
    // 和fixedDelay意思相同,只是使用字符传格式,支持占位符。例如:fixedDelayString = "${time.fixedDelay}"
	String fixedDelayString() default "";
    // 两次调用之间固定的毫秒数(不需要等待上次任务完成)
	long fixedRate() default -1;
    // 同上,支持占位符
	String fixedRateString() default "";
    // 第一次执行任务前延迟的毫秒数
	long initialDelay() default -1;
    // 同上,支持占位符
	String initialDelayString() default "";
}

Example

@Component
@EnableScheduling
public class ScheduledTask {
    @Scheduled(fixedDelay = 1000)
    public void task(){
        System.out.println("aaa");
    }
}
PrincipleProject startingScheduledAnnotationBeanPostProcessor

postProcessAfterInitialization ()

メソッドは、

@Scheduled

アノテーションを持つメソッドをスキャンします:

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||
				bean instanceof ScheduledExecutorService) {
			// Ignore AOP infrastructure such as scoped proxies.
			return bean;
		}
		Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
		if (!this.nonAnnotatedClasses.contains(targetClass) &&
				AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {
			Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
					(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
						Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
								method, Scheduled.class, Schedules.class);
						return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
					});
			if (annotatedMethods.isEmpty()) {
				this.nonAnnotatedClasses.add(targetClass);
				if (logger.isTraceEnabled()) {
					logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
				}
			}
			else {
				// Non-empty set of methods
				annotatedMethods.forEach((method, scheduledMethods) ->
                        // 调用processScheduled方法将定时任务的方法存放到任务队列中
						scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));
				if (logger.isTraceEnabled()) {
					logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean &#39;" + beanName +
							"&#39;: " + annotatedMethods);
				}
			}
		}
		return bean;
	}
	protected void processScheduled(Scheduled scheduled, Method method, Object bean) {
		try {
            // 创建任务线程
			Runnable runnable = createRunnable(bean, method);
            // 解析到定时任务方式的标记,解析到正确的参数后会设置为TRUE,如果在解析到了其他的参数就会抛出异常
			boolean processedSchedule = false;
			String errorMessage =
					"Exactly one of the &#39;cron&#39;, &#39;fixedDelay(String)&#39;, or &#39;fixedRate(String)&#39; attributes is required";
			Set<ScheduledTask> tasks = new LinkedHashSet<>(4);
			// Determine initial delay 解析第一次的延迟(解析initialDelay参数)
			long initialDelay = scheduled.initialDelay();
			String initialDelayString = scheduled.initialDelayString();
			if (StringUtils.hasText(initialDelayString)) {
                // initialDelay不能小于0
				Assert.isTrue(initialDelay < 0, "Specify &#39;initialDelay&#39; or &#39;initialDelayString&#39;, not both");
				if (this.embeddedValueResolver != null) {
					initialDelayString = this.embeddedValueResolver.resolveStringValue(initialDelayString);
				}
				if (StringUtils.hasLength(initialDelayString)) {
					try {
						initialDelay = parseDelayAsLong(initialDelayString);
					}
					catch (RuntimeException ex) {
						throw new IllegalArgumentException(
								"Invalid initialDelayString value \"" + initialDelayString + "\" - cannot parse into long");
					}
				}
			}
			// Check cron expression 解析cron表达式
			String cron = scheduled.cron();
			if (StringUtils.hasText(cron)) {
                // 解析时区
				String zone = scheduled.zone();
				if (this.embeddedValueResolver != null) {
					cron = this.embeddedValueResolver.resolveStringValue(cron);
					zone = this.embeddedValueResolver.resolveStringValue(zone);
				}
				if (StringUtils.hasLength(cron)) {
					Assert.isTrue(initialDelay == -1, "&#39;initialDelay&#39; not supported for cron triggers");
					processedSchedule = true;
					if (!Scheduled.CRON_DISABLED.equals(cron)) {
						TimeZone timeZone;
						if (StringUtils.hasText(zone)) {
							timeZone = StringUtils.parseTimeZoneString(zone);
						}
						else {
							timeZone = TimeZone.getDefault();
						}
						tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
					}
				}
			}
            // 第一次延迟参数小于0,默认为0
			// At this point we don&#39;t need to differentiate between initial delay set or not anymore
			if (initialDelay < 0) {
				initialDelay = 0;
			}
			// Check fixed delay 解析fixedDelay参数
			long fixedDelay = scheduled.fixedDelay();
			if (fixedDelay >= 0) {
				Assert.isTrue(!processedSchedule, errorMessage);
				processedSchedule = true;
				tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));
			}
			String fixedDelayString = scheduled.fixedDelayString();
			if (StringUtils.hasText(fixedDelayString)) {
				if (this.embeddedValueResolver != null) {
					fixedDelayString = this.embeddedValueResolver.resolveStringValue(fixedDelayString);
				}
				if (StringUtils.hasLength(fixedDelayString)) {
					Assert.isTrue(!processedSchedule, errorMessage);
					processedSchedule = true;
					try {
						fixedDelay = parseDelayAsLong(fixedDelayString);
					}
					catch (RuntimeException ex) {
						throw new IllegalArgumentException(
								"Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into long");
					}
					tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));
				}
			}
			// Check fixed rate 解析fixedRate参数
			long fixedRate = scheduled.fixedRate();
			if (fixedRate >= 0) {
				Assert.isTrue(!processedSchedule, errorMessage);
				processedSchedule = true;
				tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
			}
			String fixedRateString = scheduled.fixedRateString();
			if (StringUtils.hasText(fixedRateString)) {
				if (this.embeddedValueResolver != null) {
					fixedRateString = this.embeddedValueResolver.resolveStringValue(fixedRateString);
				}
				if (StringUtils.hasLength(fixedRateString)) {
					Assert.isTrue(!processedSchedule, errorMessage);
					processedSchedule = true;
					try {
						fixedRate = parseDelayAsLong(fixedRateString);
					}
					catch (RuntimeException ex) {
						throw new IllegalArgumentException(
								"Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into long");
					}
					tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
				}
			}
			// Check whether we had any attribute set
            // 如果五个参数一个也没解析到,抛出异常
			Assert.isTrue(processedSchedule, errorMessage);
			// Finally register the scheduled tasks
            // 并发控制将任务队列存入注册任务列表
			synchronized (this.scheduledTasks) {
				Set<ScheduledTask> regTasks = this.scheduledTasks.computeIfAbsent(bean, key -> new LinkedHashSet<>(4));
				regTasks.addAll(tasks);
			}
		}
		catch (IllegalArgumentException ex) {
			throw new IllegalStateException(
					"Encountered invalid @Scheduled method &#39;" + method.getName() + "&#39;: " + ex.getMessage());
		}
	}
タスクが解析されてタスク キューに追加された後、タスクは に渡されます。 ScheduledTaskRegistrar クラス ##scheduleTasksスケジュールされたタスクを環境に追加 (登録) するメソッド<pre class="brush:java;">protected void scheduleTasks() { if (this.taskScheduler == null) { //获取ScheduledExecutorService对象,实际上都是使用ScheduledThreadPoolExecutor执行定时任务调度 this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor); } if (this.triggerTasks != null) { for (TriggerTask task : this.triggerTasks) { addScheduledTask(scheduleTriggerTask(task)); } } if (this.cronTasks != null) { for (CronTask task : this.cronTasks) { addScheduledTask(scheduleCronTask(task)); } } if (this.fixedRateTasks != null) { for (IntervalTask task : this.fixedRateTasks) { addScheduledTask(scheduleFixedRateTask(task)); } } if (this.fixedDelayTasks != null) { for (IntervalTask task : this.fixedDelayTasks) { addScheduledTask(scheduleFixedDelayTask(task)); } } } private void addScheduledTask(@Nullable ScheduledTask task) { if (task != null) { this.scheduledTasks.add(task); } }</pre>

以上がJava Springでスケジュールされたタスクを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。