如何安排一个定时器在每个月的第10天运行?

huangapple go评论78阅读模式
英文:

How can I Schedule a Timer to run every 10th of the month?

问题

如何安排一个定时器每月的10号运行?

非常感谢提前帮助。

我的实际方法:

@PostConstruct
public void postConstruct()  throws Exception
{
    
    final TimerTask task = new TimerTask()
    {
        @Override
        public void run()
        {
            myprocess();
        }
    };
    final Timer timer = new Timer();
    final long delay = 0;
    final long intervalPeriod = 20000;
    // schedules the task to be run in an interval
    timer.scheduleAtFixedRate(task, delay, intervalPeriod);
}
英文:

How can I Schedule a Timer to run every 10th of the month?

Thank you very much in advance

My actual method:

    @PostConstruct
    public void postConstruct()  throws Exception
    {
        
        final TimerTask task = new TimerTask()
        {
            @Override
            public void run()
            {
                myprocess();
            }
        };
        final Timer timer = new Timer();
        final long delay = 0;
        final long intevalPeriod = 20000;
        // schedules the task to be run in an interval
        timer.scheduleAtFixedRate(task, delay,
                intevalPeriod);
    }

答案1

得分: 6

如果您正在使用Spring,可以使用 @Scheduled 注解和cron表达式。只需如下所示在bean类上注释任何公共方法:

@Scheduled(cron = "0 0 0 10 * *")
public void myprocess() {
    // 在这里执行任务
}

不要忘记在应用程序上下文中启用调度。如果您使用XML配置:

<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>

或者,如果您使用 @Configuration 类:

@Configuration
@EnableScheduling
public class SpringConfig {
    // ...
}

cron表达式 0 0 0 10 * * 的解释如下:

  • 0 - 每小时的第0分钟
  • 0 - 每天的第0小时
  • 0 - 每月的第10天
      • 任何月份
      • 任何星期几

Spring的cron表达式文档在这里:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html

这里有一些关于使用 @Scheduled 的更多信息的链接:
https://www.baeldung.com/spring-scheduled-tasks#schedule-a-task-using-cron-expressions

以及Spring官方文档:
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling-annotation-support-scheduled

英文:

If you're using Spring, you can use the @Scheduled annotation with a cron expression. Just annotate any public method on a bean class as follows:

@Scheduled(cron = &quot;0 0 0 10 * *&quot;)
public void myprocess() {
    // perform task here
}

Don't forget to enable scheduling in your application context. If you're using XML configuration:

&lt;task:annotation-driven executor=&quot;myExecutor&quot; scheduler=&quot;myScheduler&quot;/&gt;
&lt;task:executor id=&quot;myExecutor&quot; pool-size=&quot;5&quot;/&gt;
&lt;task:scheduler id=&quot;myScheduler&quot; pool-size=&quot;10&quot;/&gt;

Or, if you're using a @Configuration class:

@Configuration
@EnableScheduling
public class SpringConfig {
    ...
}

The cron expression 0 0 0 10 * * breaks down as follows:

0  - at the zeroth second of the minute
0  - at the zeroth minute of the hour
0  - at the zeroth hour of the day
10 - on the 10th day of the month
*  - any month
*  - any day of the week

Spring's docs for cron expressions are here: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html

Here's a link with some more info about using @Scheduled:
https://www.baeldung.com/spring-scheduled-tasks#schedule-a-task-using-cron-expressions

And Spring's official docs on the subject:
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling-annotation-support-scheduled

答案2

得分: 1

基于计时器的方法

如果您正在寻找一个符合"计时器概念"的基本解决方案,您可以简单地计算正确的时间间隔,然后让任务在完成后,使用正确计算的时间再次安排自己以进行下一次执行。

还可以参考在日期/时间上调用方法。代码示例如下:

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

public static ScheduledFuture<?> scheduleFor(Runnable runnable, ZonedDateTime when) {
    Instant now = Instant.now();
    // 如果需要,可以使用不同的分辨率
    long secondsUntil = ChronoUnit.SECONDS.between(now, when.toInstant());

    return scheduler.schedule(runnable, secondsUntil, TimeUnit.of(ChronoUnit.SECONDS));
}

public static ZonedDateTime nextDate() {
    return ZonedDateTime.now().plusMonths(1);
}

然后,您可以像这样创建您的任务:

public class MyTask implements Runnable {

    // ...

    @Override
    public void run() {
        // TODO 执行您的操作 ...

        // 重新安排任务
        scheduleFor(this, nextDate());
    }
}

最初触发它的方式可以是:

scheduleFor(task, ZonedDateTime.now().withDayOfMonth(10));

缺点

显然,这种基于计时器的解决方案有一个很大的缺点,即它很容易偏离和失去同步。例如,如果您的系统时间更改,或者任务执行时间太长,以至于您会漂移到下一天。

后者可以通过在任务开始时生成下一个日期来轻松缓解,而不是在任务结束时生成。

如果对您来说这些都不是问题,它很可能会按预期工作。

否则,您可能应该选择一种不同的类似于crontab的方法,其中日期被定期检查,一旦匹配,就执行任务。与"在...秒后执行"这种固定偏移执行不同。

英文:

Timer-based

If you are searching for a vanilla solution that sticks to the "timer-concept", you can just compute the correct timespan and let the task, once its done, reschedule itself again with the correct computed time for the next execution.

Also see Call method at date/time. Will look something like:

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

public static ScheduledFuture&lt;?&gt; scheduleFor(Runnable runnable, ZonedDateTime when) {
    Instant now = Instant.now();
    // Use a different resolution if desired
    long secondsUntil = ChronoUnit.SECONDS.between(now, when.toInstant());

    return scheduler.schedule(runnable, secondsUntil, TimeUnit.of(ChronoUnit.SECONDS));
}

public static ZonedDateTime nextDate() {
    return ZonedDateTime.now().plusMonths(1);
}

And then you have your task something like

public class MyTask implements Runnable {

    // ...

    @Override
    public void run() {
        // TODO Your stuff ...

        // Reschedule
        scheduleFor(this, nextDate());
    }
}

And initially trigger it like

scheduleFor(task, ZonedDateTime.now().withDayOfMonth(10));

Disadvantages

Obviously this solution, because it is timer-based, has the big disadvantage that it can easily drift and get out of sync. For example if your system time changes or if the execution of the task takes so long that you drift into the next day.

Latter can easily be mitigated by generating the next date at start of the task, instead of the end.

If all of that is not a factor for you, it will likely work as intended.

Otherwise you should probably go for a different, crontab-like approach where the date is checked periodically and soon as it matches, it executes the task. In contrast to a fixed-offset execution as in "execute in ... seconds".

huangapple
  • 本文由 发表于 2020年8月5日 03:52:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/63254175.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定