Use nanosecond precision for scheduling (aligned with calculations)
Closes gh-30666
This commit is contained in:
		
							parent
							
								
									a73ad52a8a
								
							
						
					
					
						commit
						3415b04c73
					
				| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright 2002-2022 the original author or authors.
 | 
					 * Copyright 2002-2023 the original author or authors.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 * you may not use this file except in compliance with the License.
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ import org.springframework.lang.Nullable;
 | 
				
			||||||
 * of a given task.
 | 
					 * of a given task.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Juergen Hoeller
 | 
					 * @author Juergen Hoeller
 | 
				
			||||||
 | 
					 * @author Arjen Poutsma
 | 
				
			||||||
 * @since 3.0
 | 
					 * @since 3.0
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public interface TriggerContext {
 | 
					public interface TriggerContext {
 | 
				
			||||||
| 
						 | 
					@ -78,6 +79,7 @@ public interface TriggerContext {
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Return the last <i>actual</i> execution time of the task,
 | 
						 * Return the last <i>actual</i> execution time of the task,
 | 
				
			||||||
	 * or {@code null} if not scheduled before.
 | 
						 * or {@code null} if not scheduled before.
 | 
				
			||||||
 | 
						 * @since 6.0
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	@Nullable
 | 
						@Nullable
 | 
				
			||||||
	Instant lastActualExecution();
 | 
						Instant lastActualExecution();
 | 
				
			||||||
| 
						 | 
					@ -98,6 +100,7 @@ public interface TriggerContext {
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Return the last completion time of the task,
 | 
						 * Return the last completion time of the task,
 | 
				
			||||||
	 * or {@code null} if not scheduled before.
 | 
						 * or {@code null} if not scheduled before.
 | 
				
			||||||
 | 
						 * @since 6.0
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	@Nullable
 | 
						@Nullable
 | 
				
			||||||
	Instant lastCompletion();
 | 
						Instant lastCompletion();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -211,7 +211,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
 | 
				
			||||||
	public ScheduledFuture<?> schedule(Runnable task, Instant startTime) {
 | 
						public ScheduledFuture<?> schedule(Runnable task, Instant startTime) {
 | 
				
			||||||
		Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
							Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -222,7 +222,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
 | 
				
			||||||
	public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period) {
 | 
						public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period) {
 | 
				
			||||||
		Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
							Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), initialDelay.toMillis(), period.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), initialDelay.toNanos(), period.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -232,7 +232,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period) {
 | 
						public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), 0, period.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), 0, period.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -243,7 +243,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
 | 
				
			||||||
	public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay) {
 | 
						public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay) {
 | 
				
			||||||
		Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
							Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), initialDelay.toMillis(), delay.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), initialDelay.toNanos(), delay.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -253,7 +253,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay) {
 | 
						public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), 0, delay.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), 0, delay.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright 2002-2022 the original author or authors.
 | 
					 * Copyright 2002-2023 the original author or authors.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 * you may not use this file except in compliance with the License.
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
| 
						 | 
					@ -80,7 +80,7 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			Duration initialDelay = Duration.between(this.triggerContext.getClock().instant(), this.scheduledExecutionTime);
 | 
								Duration initialDelay = Duration.between(this.triggerContext.getClock().instant(), this.scheduledExecutionTime);
 | 
				
			||||||
			this.currentFuture = this.executor.schedule(this, initialDelay.toMillis(), TimeUnit.MILLISECONDS);
 | 
								this.currentFuture = this.executor.schedule(this, initialDelay.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
			return this;
 | 
								return this;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -158,8 +158,8 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
 | 
				
			||||||
		if (this == other) {
 | 
							if (this == other) {
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS);
 | 
							long diff = getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS);
 | 
				
			||||||
		return (diff == 0 ? 0 : ((diff < 0)? -1 : 1));
 | 
							return (diff == 0 ? 0 : (diff < 0 ? -1 : 1));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -382,7 +382,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
 | 
				
			||||||
		ScheduledExecutorService executor = getScheduledExecutor();
 | 
							ScheduledExecutorService executor = getScheduledExecutor();
 | 
				
			||||||
		Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
							Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return executor.schedule(errorHandlingTask(task, false), initialDelay.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return executor.schedule(errorHandlingTask(task, false), initialDelay.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -394,7 +394,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
 | 
				
			||||||
		ScheduledExecutorService executor = getScheduledExecutor();
 | 
							ScheduledExecutorService executor = getScheduledExecutor();
 | 
				
			||||||
		Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
							Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return executor.scheduleAtFixedRate(errorHandlingTask(task, true), initialDelay.toMillis(), period.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return executor.scheduleAtFixedRate(errorHandlingTask(task, true), initialDelay.toNanos(), period.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -405,7 +405,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
 | 
				
			||||||
	public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period) {
 | 
						public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period) {
 | 
				
			||||||
		ScheduledExecutorService executor = getScheduledExecutor();
 | 
							ScheduledExecutorService executor = getScheduledExecutor();
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return executor.scheduleAtFixedRate(errorHandlingTask(task, true), 0, period.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return executor.scheduleAtFixedRate(errorHandlingTask(task, true), 0, period.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -417,7 +417,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
 | 
				
			||||||
		ScheduledExecutorService executor = getScheduledExecutor();
 | 
							ScheduledExecutorService executor = getScheduledExecutor();
 | 
				
			||||||
		Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
							Duration initialDelay = Duration.between(this.clock.instant(), startTime);
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), initialDelay.toMillis(), delay.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), initialDelay.toNanos(), delay.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					@ -428,7 +428,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
 | 
				
			||||||
	public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay) {
 | 
						public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay) {
 | 
				
			||||||
		ScheduledExecutorService executor = getScheduledExecutor();
 | 
							ScheduledExecutorService executor = getScheduledExecutor();
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), 0, delay.toMillis(), TimeUnit.MILLISECONDS);
 | 
								return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), 0, delay.toNanos(), TimeUnit.NANOSECONDS);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch (RejectedExecutionException ex) {
 | 
							catch (RejectedExecutionException ex) {
 | 
				
			||||||
			throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
								throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -485,7 +485,7 @@ public class ScheduledTaskRegistrar implements ScheduledTaskHolder, Initializing
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (this.taskScheduler != null) {
 | 
							if (this.taskScheduler != null) {
 | 
				
			||||||
			Duration initialDelay = task.getInitialDelayDuration();
 | 
								Duration initialDelay = task.getInitialDelayDuration();
 | 
				
			||||||
			if (initialDelay.toMillis() > 0) {
 | 
								if (initialDelay.toNanos() > 0) {
 | 
				
			||||||
				Instant startTime = this.taskScheduler.getClock().instant().plus(initialDelay);
 | 
									Instant startTime = this.taskScheduler.getClock().instant().plus(initialDelay);
 | 
				
			||||||
				scheduledTask.future =
 | 
									scheduledTask.future =
 | 
				
			||||||
						this.taskScheduler.scheduleAtFixedRate(task.getRunnable(), startTime, task.getIntervalDuration());
 | 
											this.taskScheduler.scheduleAtFixedRate(task.getRunnable(), startTime, task.getIntervalDuration());
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,18 +57,12 @@ public final class CronExpression {
 | 
				
			||||||
	private final String expression;
 | 
						private final String expression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private CronExpression(
 | 
						private CronExpression(CronField seconds, CronField minutes, CronField hours,
 | 
				
			||||||
			CronField seconds,
 | 
								CronField daysOfMonth, CronField months, CronField daysOfWeek, String expression) {
 | 
				
			||||||
			CronField minutes,
 | 
					 | 
				
			||||||
			CronField hours,
 | 
					 | 
				
			||||||
			CronField daysOfMonth,
 | 
					 | 
				
			||||||
			CronField months,
 | 
					 | 
				
			||||||
			CronField daysOfWeek,
 | 
					 | 
				
			||||||
			String expression) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// reverse order, to make big changes first
 | 
							// Reverse order, to make big changes first.
 | 
				
			||||||
		// to make sure we end up at 0 nanos, we add an extra field
 | 
							// To make sure we end up at 0 nanos, we add an extra field.
 | 
				
			||||||
		this.fields = new CronField[]{daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
 | 
							this.fields = new CronField[] {daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
 | 
				
			||||||
		this.expression = expression;
 | 
							this.expression = expression;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -267,27 +261,19 @@ public final class CronExpression {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(@Nullable Object other) {
 | 
				
			||||||
 | 
							return (this == other || (other instanceof CronExpression that &&
 | 
				
			||||||
 | 
									Arrays.equals(this.fields, that.fields)));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public int hashCode() {
 | 
						public int hashCode() {
 | 
				
			||||||
		return Arrays.hashCode(this.fields);
 | 
							return Arrays.hashCode(this.fields);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public boolean equals(@Nullable Object o) {
 | 
					 | 
				
			||||||
		if (this == o) {
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (o instanceof CronExpression other) {
 | 
					 | 
				
			||||||
			return Arrays.equals(this.fields, other.fields);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Return the expression string used to create this {@code CronExpression}.
 | 
						 * Return the expression string used to create this {@code CronExpression}.
 | 
				
			||||||
	 * @return the expression string
 | 
					 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public String toString() {
 | 
						public String toString() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ public class CronTrigger implements Trigger {
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Determine the next execution time according to the given trigger context.
 | 
						 * Determine the next execution time according to the given trigger context.
 | 
				
			||||||
	 * <p>Next execution times are calculated based on the
 | 
						 * <p>Next execution times are calculated based on the
 | 
				
			||||||
	 * {@linkplain TriggerContext#lastCompletionTime completion time} of the
 | 
						 * {@linkplain TriggerContext#lastCompletion completion time} of the
 | 
				
			||||||
	 * previous execution; therefore, overlapping executions won't occur.
 | 
						 * previous execution; therefore, overlapping executions won't occur.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
| 
						 | 
					@ -114,8 +114,9 @@ public class CronTrigger implements Trigger {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public boolean equals(@Nullable Object obj) {
 | 
						public boolean equals(@Nullable Object other) {
 | 
				
			||||||
		return (this == obj || (obj instanceof CronTrigger that && this.expression.equals(that.expression)));
 | 
							return (this == other || (other instanceof CronTrigger that &&
 | 
				
			||||||
 | 
									this.expression.equals(that.expression)));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue