有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使线程在x:00X:15X:30和x:45运行在2:00做一些不同的事情

我有一个计时器线程,它需要在一天中的特定时刻运行,以便对数据库执行增量复制。现在它按小时运行,每小时15分钟,每小时30分钟,每小时45分钟。这是我的代码,工作正常:

public class TimerRunner implements Runnable {

    private static final Semaphore lock = new Semaphore(1);

    private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    public static void initialize() {
        long delay = getDelay();
        executor.schedule(new TimerRunner(), delay, TimeUnit.SECONDS);
    }

    public static void destroy() {
        executor.shutdownNow();
    }

    private static long getDelay() {
        Calendar now = Calendar.getInstance();
        long p = 15 * 60; // run at 00, 15, 30 and 45 minutes past the hour
        long second = now.get(Calendar.MINUTE) * 60 + now.get(Calendar.SECOND);
        return p - (second % p);
    }

    public static void replicate() {
        if (lock.tryAcquire()) {
            try {
                Thread t = new Thread(new Runnable() {
                    public void run() {
                        try {
                            // here is where the magic happens
                        } finally {
                            lock.release();
                        }
                    }
                });
                t.start();
            } catch (Exception e) {
                lock.release();
            }
        } else {
            throw new IllegalStateException("already running a replicator");
        }
    }

    public void run() {
        try {
            TimerRunner.replicate();
        } finally {
            long delay = getDelay();
            executor.schedule(new TimerRunner(), delay, TimeUnit.SECONDS);
        }
    }

}

这个过程是通过在服务器启动时调用TimerRunner.initialize()并调用TimerRunner.destroy()来启动的

我已经创建了一个完整的复制过程(而不是增量复制),我希望在一天中的某个时刻(比如凌晨2点)运行该过程。如何更改上述代码以实现此目的?我认为这应该是非常简单的事情,比如如果现在是凌晨2点左右,而且我已经很长时间没有做完整的复制了,那么现在就做吧,但是我不能得到正确的if

请注意,有时复制过程需要更长的时间才能完成。有时超过15分钟,造成凌晨2:00左右跑步时出现问题


共 (2) 个答案

  1. # 1 楼答案

    嗯,如果它做了一些不同的事情,它不应该是相同的可运行的。创建一些泛型抽象类和两个子类,每个子类都有特定的行为。然后让调度逻辑在适当的时间调度适当的线程

    否则,您的对象有两个职责,需要了解调度

    我个人也会将调度逻辑从您当前的getDelay()中取出,放入一些replication scheduling manager对象中,该对象也会维护状态(例如,最近执行的内容)

    最后,您可能想为您的调度程序使用库中的东西,我觉得您正在重新发明一些轮子

  2. # 2 楼答案

    不要构建自己的计划程序,使用现有的计划程序

    如果您想在Java中执行此操作,请使用quartz和调度2个单独的任务来执行在不同调度上运行的增量备份和完整备份

    但是在您的情况下,一个简单的cron脚本就可以了。如果您在Windows上运行,请在Windows帮助文件中搜索Scheduled Tasks

    编辑
    以下是避免同时运行完整和增量的crontab:

    */15 0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 * * * /path/to/run-incremental-backup.sh
    15,30,45 1 * * * /path/to/run-incremental-backup.sh
    0 1 * * * /path/to/run-full-backup.sh
    

    在shell脚本中,设置java环境并运行负责任务的java程序

    Quartz调度程序可以进行非常精细的调整,其中一个标准调度程序完全模仿crontab。我将此作为练习留给读者

    顺便说一句,我已安排您的完整备份在凌晨1点运行,请参见下面的原因

    关于夏令时的注意事项
    我不知道你在世界上的什么地方,如果你是少数幸运的人之一,你没有夏令时,否则就去当地时区管理局查询。在北美,标准到日光发生在凌晨2:00,标准到日光发生在凌晨3:00,因此,如果您的完全备份计划在凌晨2:00进行,那么一年中的某一天(S到D)您的完全备份将不会运行,而另一天(D到S)它将运行两次